Import OL

This commit is contained in:
eabdullin 2025-05-05 12:29:59 +03:00
parent 197cfad5ef
commit 04d9de308a
12 changed files with 1605 additions and 4 deletions

View File

@ -0,0 +1,46 @@
From 287213b44674cac24ad4eb09dbf2c4a21538462a Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 10 Mar 2025 18:52:08 +0000
Subject: [PATCH] lib: Print kernel utsname in debug output
Useful for debugging problems caused by the host kernel. In
particular we were looking at a problem with passt creating a user
namespace but didn't know what exact kernel was being used.
(cherry picked from commit 31fa712aa07190f2c5ed789712b92b4be2d51488)
(cherry picked from commit 19c4d1c8b9f278e054594660b5392d6c08a59d8f)
---
lib/launch.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/launch.c b/lib/launch.c
index bd0526c9..22196819 100644
--- a/lib/launch.c
+++ b/lib/launch.c
@@ -36,6 +36,7 @@
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <errno.h>
#include <assert.h>
#include <libintl.h>
@@ -92,6 +93,7 @@ guestfs_impl_launch (guestfs_h *g)
struct backend *b;
CLEANUP_FREE char *backend = guestfs_get_backend (g);
int mask;
+ struct utsname utsname;
debug (g, "launch: program=%s", g->program);
if (STRNEQ (g->identifier, ""))
@@ -108,6 +110,10 @@ guestfs_impl_launch (guestfs_h *g)
if (mask >= 0)
debug (g, "launch: umask=0%03o", (unsigned) mask);
debug (g, "launch: euid=%ju", (uintmax_t) geteuid ());
+ if (uname (&utsname) == 0)
+ debug (g, "launch: host: %s %s %s %s %s",
+ utsname.sysname, utsname.nodename, utsname.release,
+ utsname.version, utsname.machine);
}
/* Launch the appliance. */

View File

@ -0,0 +1,70 @@
From 0de9a79780bffab93edbf2a609fc33c3afd02605 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 10:01:33 +0100
Subject: [PATCH] daemon: inspect: Add some debugging of /usr merging
(cherry picked from commit 2d1e8941301373d04a436333219358a72f9660f1)
(cherry picked from commit 68cecb64758b8ff6d3af842721cb7cf706cb5d0c)
---
daemon/inspect.ml | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/daemon/inspect.ml b/daemon/inspect.ml
index f6e0ce1f..bec9d567 100644
--- a/daemon/inspect.ml
+++ b/daemon/inspect.ml
@@ -47,18 +47,21 @@ let rec inspect_os () =
* multiple filesystems. Gather all the inspected information in the
* inspect_fs struct of the root filesystem.
*)
+ eprintf "inspect_os: collect_coreos_inspection_info\n%!";
let fses = collect_coreos_inspection_info fses in
(* Check if the same filesystem was listed twice as root in fses.
* This may happen for the *BSD root partition where an MBR partition
* is a shadow of the real root partition probably /dev/sda5
*)
+ eprintf "inspect_os: check_for_duplicated_bsd_root\n%!";
let fses = check_for_duplicated_bsd_root fses in
(* For Linux guests with a separate /usr filesystem, merge some of the
* inspected information in that partition to the inspect_fs struct
* of the root filesystem.
*)
+ eprintf "inspect_os: collect_linux_inspection_info\n%!";
let fses = collect_linux_inspection_info fses in
(* Save what we found in a global variable. *)
@@ -194,6 +197,9 @@ and collect_linux_inspection_info fses =
* or other ways to identify the OS).
*)
and collect_linux_inspection_info_for fses root =
+ eprintf "inspect_os: collect_linux_inspection_info_for %s\n"
+ (string_of_location root.fs_location);
+
let root_fstab =
match root with
| { role = RoleRoot { fstab = f } } -> f
@@ -207,14 +213,21 @@ and collect_linux_inspection_info_for fses root =
(* This checks that this usr is found in the fstab of
* the root filesystem.
*)
+ eprintf "inspect_os: checking if %s found in fstab of this root\n"
+ (string_of_location usr_mp);
List.exists (
fun (mountable, _) ->
+ eprintf "inspect_os: collect_linux_inspection_info_for: \
+ compare %s = %s\n"
+ (Mountable.to_string usr_mp.mountable)
+ (Mountable.to_string mountable);
usr_mp.mountable = mountable
) root_fstab
| _ -> false
) fses in
- eprintf "collect_linux_inspection_info_for: merging:\n%sinto:\n%s"
+ eprintf "inspect_os: collect_linux_inspection_info_for: merging:\n\
+ %sinto:\n%s"
(string_of_fs usr) (string_of_fs root);
merge usr root;
root

View File

@ -0,0 +1,491 @@
From 983159e5f0d31ae64dfc0a584c089699315196a6 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 11:35:13 +0100
Subject: [PATCH] generator: Implement struct FDevice type
This acts just like FString except that we do reverse device name
translation on it. The only use is in the 'pvs-full' API where we
will use it (in a subsequent commit) to reverse translate the pv_name
field (a device name) before returning it from the daemon.
Compare this to the 'pvs' API which also returns a list of device
names, but using the generator's 'RStructList (RDevice,...)' return
type, where RDevice is similarly reverse translated.
Note in the library-side bindings, because the name has already been
translated in the daemon, we just treat it exactly the same as
FString. The vast majority of this patch is this mechanical change.
(cherry picked from commit 0ff73a42c7f4f309fbab11ea2e89ee6f0501367d)
(cherry picked from commit 4e27b259c166d87a57d133a79b8eed3b556288b8)
---
generator/GObject.ml | 6 +++---
generator/OCaml.ml | 6 ++----
generator/XDR.ml | 2 +-
generator/c.ml | 20 +++++++++-----------
generator/csharp.ml | 2 +-
generator/daemon.ml | 30 ++++++++++++++++++++++++++----
generator/erlang.ml | 2 +-
generator/golang.ml | 4 ++--
generator/java.ml | 7 ++++---
generator/lua.ml | 2 +-
generator/perl.ml | 4 ++--
generator/php.ml | 4 ++--
generator/python.ml | 2 +-
generator/ruby.ml | 4 ++--
generator/rust.ml | 6 +++---
generator/types.ml | 1 +
generator/types.mli | 1 +
17 files changed, 62 insertions(+), 41 deletions(-)
diff --git a/generator/GObject.ml b/generator/GObject.ml
index 6c74b31b..e7462c0e 100644
--- a/generator/GObject.ml
+++ b/generator/GObject.ml
@@ -206,7 +206,7 @@ let generate_gobject_struct_header filename typ cols () =
pr " * @%s: An unsigned 64-bit integer\n" n
| n, FInt64 ->
pr " * @%s: A signed 64-bit integer\n" n
- | n, FString ->
+ | n, (FString|FDevice) ->
pr " * @%s: A NULL-terminated string\n" n
| n, FBuffer ->
pr " * @%s: A GByteArray\n" n
@@ -231,7 +231,7 @@ let generate_gobject_struct_header filename typ cols () =
pr " guint64 %s;\n" n
| n, FInt64 ->
pr " gint64 %s;\n" n
- | n, FString ->
+ | n, (FString|FDevice) ->
pr " gchar *%s;\n" n
| n, FBuffer ->
pr " GByteArray *%s;\n" n
@@ -1228,7 +1228,7 @@ guestfs_session_close (GuestfsSession *session, GError **err)
| n, FUUID ->
pr "%smemcpy (%s%s, %s%s, sizeof (%s%s));\n"
indent dst n src n dst n
- | n, FString ->
+ | n, (FString|FDevice) ->
pr "%sif (%s%s) %s%s = g_strdup (%s%s);\n"
indent src n dst n src n
| n, FBuffer ->
diff --git a/generator/OCaml.ml b/generator/OCaml.ml
index 1e6f603a..4ef07e27 100644
--- a/generator/OCaml.ml
+++ b/generator/OCaml.ml
@@ -512,7 +512,7 @@ copy_table (char * const * argv)
List.iteri (
fun i col ->
(match col with
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " v = caml_copy_string (%s->%s);\n" typ name
| name, FBuffer ->
pr " v = caml_alloc_initialized_string (%s->%s_len, %s->%s);\n"
@@ -839,9 +839,7 @@ and generate_ocaml_structure_decls () =
pr "type %s = {\n" typ;
List.iter (
function
- | name, FString -> pr " %s : string;\n" name
- | name, FBuffer -> pr " %s : string;\n" name
- | name, FUUID -> pr " %s : string;\n" name
+ | name, (FString|FDevice|FBuffer|FUUID) -> pr " %s : string;\n" name
| name, (FBytes|FInt64|FUInt64) -> pr " %s : int64;\n" name
| name, (FInt32|FUInt32) -> pr " %s : int32;\n" name
| name, FChar -> pr " %s : char;\n" name
diff --git a/generator/XDR.ml b/generator/XDR.ml
index 566ba69e..e71d97f5 100644
--- a/generator/XDR.ml
+++ b/generator/XDR.ml
@@ -66,7 +66,7 @@ let generate_xdr () =
pr "struct guestfs_int_%s {\n" typ;
List.iter (function
| name, FChar -> pr " char %s;\n" name
- | name, FString -> pr " string %s<>;\n" name
+ | name, (FString|FDevice) -> pr " string %s<>;\n" name
| name, FBuffer -> pr " opaque %s<>;\n" name
| name, FUUID -> pr " opaque %s[32];\n" name
| name, FInt32 -> pr " int %s;\n" name
diff --git a/generator/c.ml b/generator/c.ml
index 0391dd3d..e850885e 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -352,7 +352,7 @@ and generate_structs_pod () =
| name, FInt32 -> pr " int32_t %s;\n" name
| name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
| name, FInt64 -> pr " int64_t %s;\n" name
- | name, FString -> pr " char *%s;\n" name
+ | name, (FString|FDevice) -> pr " char *%s;\n" name
| name, FBuffer ->
pr " /* The next two fields describe a byte array. */\n";
pr " uint32_t %s_len;\n" name;
@@ -609,7 +609,7 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private (guestfs_h *g, const char *
List.iter (
function
| name, FChar -> pr " char %s;\n" name
- | name, FString -> pr " char *%s;\n" name
+ | name, (FString|FDevice) -> pr " char *%s;\n" name
| name, FBuffer ->
pr " uint32_t %s_len;\n" name;
pr " char *%s;\n" name
@@ -926,7 +926,7 @@ and generate_client_structs_compare () =
fun { s_name = typ; s_cols = cols } ->
let has_nonnumeric_cols =
let nonnumeric = function
- | _,(FString|FUUID|FBuffer) -> true
+ | _,(FString|FDevice|FUUID|FBuffer) -> true
| _,(FChar|FUInt32|FInt32|FUInt64|FBytes|FInt64|FOptPercent) -> false
in
List.exists nonnumeric cols in
@@ -942,7 +942,7 @@ and generate_client_structs_compare () =
);
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " r = strcmp (s1->%s, s2->%s);\n" name name;
pr " if (r != 0) return r;\n"
| name, FBuffer ->
@@ -1011,7 +1011,7 @@ and generate_client_structs_copy () =
fun { s_name = typ; s_cols = cols } ->
let has_boxed_cols =
let boxed = function
- | _,(FString|FBuffer) -> true
+ | _,(FString|FDevice|FBuffer) -> true
| _,(FChar|FUUID|FUInt32|FInt32|FUInt64|FBytes|FInt64|FOptPercent) ->
false
in
@@ -1024,8 +1024,7 @@ and generate_client_structs_copy () =
pr "{\n";
List.iter (
function
- | name, FString
- | name, FBuffer -> pr " free (s->%s);\n" name
+ | name, (FString|FDevice|FBuffer) -> pr " free (s->%s);\n" name
| _, FChar
| _, FUUID
| _, FUInt32
@@ -1048,8 +1047,7 @@ and generate_client_structs_copy () =
pr "\n";
List.iter (
function
- | name, FString
- | name, FBuffer -> pr " out->%s = NULL;\n" name
+ | name, (FString|FDevice|FBuffer) -> pr " out->%s = NULL;\n" name
| _, FChar
| _, FUUID
| _, FUInt32
@@ -1061,7 +1059,7 @@ and generate_client_structs_copy () =
) cols;
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " out->%s = strdup (inp->%s);\n" name name;
pr " if (out->%s == NULL) goto error;\n" name
| name, FBuffer ->
@@ -1244,7 +1242,7 @@ and generate_client_structs_print_c () =
);
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " fprintf (dest, \"%%s%s: %%s%%s\", indent, %s->%s, linesep);\n"
name typ name
| name, FUUID ->
diff --git a/generator/csharp.ml b/generator/csharp.ml
index 43579df5..6ab6c3c9 100644
--- a/generator/csharp.ml
+++ b/generator/csharp.ml
@@ -119,7 +119,7 @@ namespace Guestfs
List.iter (
function
| name, FChar -> pr " char %s;\n" name
- | name, FString -> pr " string %s;\n" name
+ | name, (FString | FDevice) -> pr " string %s;\n" name
| name, FBuffer ->
pr " uint %s_len;\n" name;
pr " string %s;\n" name
diff --git a/generator/daemon.ml b/generator/daemon.ml
index 78a2412d..0218d3e5 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -447,15 +447,37 @@ let generate_daemon_stubs actions () =
pr " ret.%s.%s_val = r;\n" n n;
pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
name
- | RStruct (n, _) ->
+ | RStruct (n, typ) ->
+ (* XXX RStruct containing an FDevice field would require
+ * reverse device name translation. That is not implemented.
+ * See also RStructList immediately below this.
+ *)
+ let cols = (Structs.lookup_struct typ).s_cols in
+ assert (not (List.exists
+ (function (_, FDevice) -> true | _ -> false) cols));
pr " struct guestfs_%s_ret ret;\n" name;
pr " ret.%s = *r;\n" n;
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
name;
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
name
- | RStructList (n, _) ->
+ | RStructList (n, typ) ->
pr " struct guestfs_%s_ret ret;\n" name;
+ let cols = (Structs.lookup_struct typ).s_cols in
+ List.iter (
+ function
+ | (fname, FDevice) ->
+ pr " for (size_t i = 0; i < r->guestfs_int_%s_list_len; ++i) {\n"
+ typ;
+ pr " char *field = r->guestfs_int_%s_list_val[i].%s;\n"
+ typ fname;
+ pr " char *rr = reverse_device_name_translation (field);\n";
+ pr " if (!rr) abort ();\n";
+ pr " free (field);\n";
+ pr " r->guestfs_int_%s_list_val[i].%s = rr;\n" typ fname;
+ pr " }\n";
+ | _ -> ()
+ ) cols;
pr " ret.%s = *r;\n" n;
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
name;
@@ -624,7 +646,7 @@ let generate_daemon_caml_stubs () =
fun i ->
pr " v = Field (retv, %d);\n" i;
function
- | n, (FString|FUUID) ->
+ | n, (FString|FDevice|FUUID) ->
pr " ret->%s = strdup (String_val (v));\n" n;
pr " if (ret->%s == NULL) return NULL;\n" n
| n, FBuffer ->
@@ -991,7 +1013,7 @@ let generate_daemon_lvm_tokenization () =
pr " if (*p) next = p+1; else next = NULL;\n";
pr " *p = '\\0';\n";
(match coltype with
- | FString ->
+ | FString | FDevice ->
pr " r->%s = strdup (tok);\n" name;
pr " if (r->%s == NULL) {\n" name;
pr " perror (\"strdup\");\n";
diff --git a/generator/erlang.ml b/generator/erlang.ml
index 65af75aa..864b3ff0 100644
--- a/generator/erlang.ml
+++ b/generator/erlang.ml
@@ -286,7 +286,7 @@ and generate_erlang_structs () =
List.iteri (
fun i col ->
(match col with
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " if (ei_x_encode_string (buff, %s->%s) != 0) return -1;\n" typ name
| name, FBuffer ->
pr " if (ei_x_encode_string_len (buff, %s->%s, %s->%s_len) != 0) return -1;\n"
diff --git a/generator/golang.ml b/generator/golang.ml
index 0d6a9236..a5b39f5d 100644
--- a/generator/golang.ml
+++ b/generator/golang.ml
@@ -248,7 +248,7 @@ func return_hashtable (argv **C.char) map[string]string {
let n = String.capitalize_ascii n in
match field with
| FChar -> pr " %s byte\n" n
- | FString -> pr " %s string\n" n
+ | FString | FDevice -> pr " %s string\n" n
| FBuffer -> pr " %s []byte\n" n
| FUInt32 -> pr " %s uint32\n" n
| FInt32 -> pr " %s int32\n" n
@@ -267,7 +267,7 @@ func return_hashtable (argv **C.char) map[string]string {
let gon = String.capitalize_ascii n in
match field with
| FChar -> pr " r.%s = byte (c.%s)\n" gon n
- | FString -> pr " r.%s = C.GoString (c.%s)\n" gon n
+ | FString | FDevice -> pr " r.%s = C.GoString (c.%s)\n" gon n
| FBuffer ->
pr " r.%s = C.GoBytes (unsafe.Pointer (c.%s), C.int (c.%s_len))\n"
gon n n
diff --git a/generator/java.ml b/generator/java.ml
index afcddf90..4b74203a 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -560,6 +560,7 @@ public class %s {
List.iter (
function
| name, FString
+ | name, FDevice
| name, FUUID
| name, FBuffer -> pr " public String %s;\n" name
| name, (FBytes|FUInt64|FInt64) -> pr " public long %s;\n" name
@@ -947,7 +948,7 @@ and generate_java_struct_return typ jtyp cols =
pr " jr = (*env)->AllocObject (env, cl);\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
| name, FUUID ->
@@ -997,7 +998,7 @@ and generate_java_struct_list_return typ jtyp cols =
fun (name, ftyp) ->
(* Get the field ID in 'fl'. *)
let java_field_type = match ftyp with
- | FString | FUUID | FBuffer -> "Ljava/lang/String;"
+ | FString | FDevice | FUUID | FBuffer -> "Ljava/lang/String;"
| FBytes | FUInt64 | FInt64 -> "J"
| FUInt32 | FInt32 -> "I"
| FOptPercent -> "F"
@@ -1007,7 +1008,7 @@ and generate_java_struct_list_return typ jtyp cols =
(* Assign the value to this field. *)
match ftyp with
- | FString ->
+ | FString | FDevice ->
pr " (*env)->SetObjectField (env, jfl, fl,\n";
pr " (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
| FUUID ->
diff --git a/generator/lua.ml b/generator/lua.ml
index 0d7e63be..685645ab 100644
--- a/generator/lua.ml
+++ b/generator/lua.ml
@@ -824,7 +824,7 @@ push_event (lua_State *L, uint64_t event)
(match field with
| FChar ->
pr " lua_pushlstring (L, &v->%s, 1);\n" n
- | FString ->
+ | FString | FDevice ->
pr " lua_pushstring (L, v->%s);\n" n
| FBuffer ->
pr " lua_pushlstring (L, v->%s, v->%s_len);\n" n n
diff --git a/generator/perl.ml b/generator/perl.ml
index 8b9834ef..e0edc249 100644
--- a/generator/perl.ml
+++ b/generator/perl.ml
@@ -607,7 +607,7 @@ and generate_perl_struct_list_code typ cols name style =
pr " hv = newHV ();\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " (void) hv_store (hv, \"%s\", %d, newSVpv (r->val[i].%s, 0), 0);\n"
name (String.length name) name
| name, FUUID ->
@@ -645,7 +645,7 @@ and generate_perl_struct_code typ cols name style =
pr " PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
match col with
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " PUSHs (sv_2mortal (newSVpv (r->%s, 0)));\n"
name
| name, FBuffer ->
diff --git a/generator/php.ml b/generator/php.ml
index 99ec66c7..5023e0c5 100644
--- a/generator/php.ml
+++ b/generator/php.ml
@@ -616,7 +616,7 @@ and generate_php_struct_code typ cols =
pr " array_init (return_value);\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " guestfs_add_assoc_string (return_value, \"%s\", r->%s, 1);\n" name name
| name, FBuffer ->
pr " guestfs_add_assoc_stringl (return_value, \"%s\", r->%s, r->%s_len, 1);\n"
@@ -650,7 +650,7 @@ and generate_php_struct_list_code typ cols =
pr " array_init (z_elem);\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " guestfs_add_assoc_string (z_elem, \"%s\", r->val[c].%s, 1);\n"
name name
| name, FBuffer ->
diff --git a/generator/python.ml b/generator/python.ml
index ad02ea93..5534e74a 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -168,7 +168,7 @@ and generate_python_structs () =
pr " return NULL;\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " value = guestfs_int_py_fromstring (%s->%s);\n" typ name;
pr " if (value == NULL)\n";
pr " goto err;\n";
diff --git a/generator/ruby.ml b/generator/ruby.ml
index be3238f6..ea5a3194 100644
--- a/generator/ruby.ml
+++ b/generator/ruby.ml
@@ -526,7 +526,7 @@ and generate_ruby_struct_code typ cols =
pr " volatile VALUE rv = rb_hash_new ();\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
| name, FBuffer ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
@@ -556,7 +556,7 @@ and generate_ruby_struct_list_code typ cols =
pr " volatile VALUE hv = rb_hash_new ();\n";
List.iter (
function
- | name, FString ->
+ | name, (FString|FDevice) ->
pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
| name, FBuffer ->
pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, r->val[i].%s_len));\n" name name name
diff --git a/generator/rust.ml b/generator/rust.ml
index 1f5cefa6..f4dcfd72 100644
--- a/generator/rust.ml
+++ b/generator/rust.ml
@@ -115,7 +115,7 @@ extern \"C\" {
List.iter (
function
| n, FChar -> pr " pub %s: i8,\n" n
- | n, FString -> pr " pub %s: String,\n" n
+ | n, (FString|FDevice) -> pr " pub %s: String,\n" n
| n, FBuffer -> pr " pub %s: Vec<u8>,\n" n
| n, FUInt32 -> pr " pub %s: u32,\n" n
| n, FInt32 -> pr " pub %s: i32,\n" n
@@ -130,7 +130,7 @@ extern \"C\" {
List.iter (
function
| n, FChar -> pr " %s: c_char,\n" n
- | n, FString -> pr " %s: *const c_char,\n" n
+ | n, (FString|FDevice) -> pr " %s: *const c_char,\n" n
| n, FBuffer ->
pr " %s_len: usize,\n" n;
pr " %s: *const c_char,\n" n;
@@ -154,7 +154,7 @@ extern \"C\" {
match x with
| n, FChar ->
pr "%s: (*raw).%s as i8,\n" n n;
- | n, FString ->
+ | n, (FString|FDevice) ->
pr "%s: char_ptr_to_string((*raw).%s)?,\n" n n;
| n, FBuffer ->
pr "%s: slice::from_raw_parts((*raw).%s as *const u8, (*raw).%s_len).to_vec(),\n" n n n
diff --git a/generator/types.ml b/generator/types.ml
index d9b00885..c901aa73 100644
--- a/generator/types.ml
+++ b/generator/types.ml
@@ -215,6 +215,7 @@ let defaults = { name = "";
type field =
| FChar (* C 'char' (really, a 7 bit byte). *)
| FString (* nul-terminated ASCII string, NOT NULL. *)
+ | FDevice (* device name, needs reverse transl. *)
| FBuffer (* opaque buffer of bytes, (char *, int) pair *)
| FUInt32
| FInt32
diff --git a/generator/types.mli b/generator/types.mli
index 0ce0d33b..0a4752d5 100644
--- a/generator/types.mli
+++ b/generator/types.mli
@@ -413,6 +413,7 @@ val defaults : action
type field =
| FChar (** C 'char' (really, a 7 bit byte). *)
| FString (** nul-terminated ASCII string, NOT NULL. *)
+ | FDevice (** device name, needs reverse transl. *)
| FBuffer (** opaque buffer of bytes, (char *, int) pair*)
| FUInt32
| FInt32

View File

@ -0,0 +1,69 @@
From b7286e1ac371d27d24f88aa646f6cd726443d926 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 11:50:37 +0100
Subject: [PATCH] generator: Use new FDevice type for the pvs-full pv_name
field
Remove the code which did explicit reverse device name translation,
and use the generator's code instead.
(cherry picked from commit 5a16d1120fb7b046974abde43b1c40250bfd1a95)
(cherry picked from commit b306532e7a4a3f235b24e5dab22ab36b849ac886)
---
daemon/lvm.c | 29 +----------------------------
generator/structs.ml | 2 +-
2 files changed, 2 insertions(+), 29 deletions(-)
diff --git a/daemon/lvm.c b/daemon/lvm.c
index b8c01f71..7e76e17c 100644
--- a/daemon/lvm.c
+++ b/daemon/lvm.c
@@ -146,34 +146,7 @@ do_vgs (void)
guestfs_int_lvm_pv_list *
do_pvs_full (void)
{
- guestfs_int_lvm_pv_list *r;
- size_t i;
- char *din, *dout;
-
- r = parse_command_line_pvs ();
- if (r == NULL)
- /* parse_command_line_pvs has already called reply_with_error */
- return NULL;
-
- /* The pv_name fields contain device names which must be reverse
- * translated. The problem here is that the generator does not have
- * a "FMountable" field type in types.mli.
- */
- for (i = 0; i < r->guestfs_int_lvm_pv_list_len; ++i) {
- din = r->guestfs_int_lvm_pv_list_val[i].pv_name;
- if (din) {
- dout = reverse_device_name_translation (din);
- if (!dout) {
- /* reverse_device_name_translation has already called reply_with_error*/
- /* XXX memory leak here */
- return NULL;
- }
- r->guestfs_int_lvm_pv_list_val[i].pv_name = dout;
- free (din);
- }
- }
-
- return r;
+ return parse_command_line_pvs ();
}
guestfs_int_lvm_vg_list *
diff --git a/generator/structs.ml b/generator/structs.ml
index c1408804..93a3ed03 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -35,7 +35,7 @@ type struc = {
* we have to pull out the LVM columns separately here.
*)
let lvm_pv_cols = [
- "pv_name", FString;
+ "pv_name", FDevice;
"pv_uuid", FUUID;
"pv_fmt", FString;
"pv_size", FBytes;

View File

@ -0,0 +1,47 @@
From a3ac31c6dc06a83086c1de2f013ce907883b343b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 10:13:52 +0100
Subject: [PATCH] daemon: inspect: Resolve Ubuntu 22+ /dev/disk/by-uuid/ in
fstab
Ubuntu 22= uses /dev/disk/by-uuid/ followed by a filesystem UUID in
fstab entries. Resolve these to mountables.
A typical fstab entry looks like this:
# /boot was on /dev/vda2 during curtin installation
/dev/disk/by-uuid/b4e56462-5a64-4272-b76d-f5e58bd8f128 /boot ext4 defaults 0 1
The comment is generated by the installer and appears in the fstab.
This entry would be translated to /dev/sda2.
(cherry picked from commit 7a1ffd744b12c4c79fa1b78341ea714d831f4205)
(cherry picked from commit 0d466cb25e86ab6f7f6838d35afb37b99f83e0e4)
---
daemon/inspect_fs_unix_fstab.ml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/daemon/inspect_fs_unix_fstab.ml b/daemon/inspect_fs_unix_fstab.ml
index f5817a31..45c62175 100644
--- a/daemon/inspect_fs_unix_fstab.ml
+++ b/daemon/inspect_fs_unix_fstab.ml
@@ -394,6 +394,19 @@ and resolve_fstab_device spec md_map os_type =
resolve_diskbyid part default
)
+ (* Ubuntu 22+ uses /dev/disk/by-uuid/ followed by a UUID. *)
+ else if String.is_prefix spec "/dev/disk/by-uuid/" then (
+ debug_matching "diskbyuuid";
+ let uuid = String.sub spec 18 (String.length spec - 18) in
+ try
+ (* Try a filesystem UUID. Unclear if this could be a partition UUID
+ * as well, but in the Ubuntu guest I tried it was an fs UUID XXX.
+ *)
+ Mountable.of_device (Findfs.findfs_uuid uuid)
+ with
+ Failure _ -> default
+ )
+
else if PCRE.matches re_freebsd_gpt spec then (
debug_matching "FreeBSD GPT";
(* group 1 (type) is not used *)

View File

@ -0,0 +1,44 @@
From af2e259ff72d5a41c9cfe453a67ecff77190cbc6 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 13:19:17 +0100
Subject: [PATCH] generator: Fix implementation of FUUID for OCaml functions
This was implemented wrongly. In the XDR protocol, UUIDs are fixed
buffers of length 32. We can just use memcpy to copy from the OCaml
string to the UUID, but we have to ensure the string length returned
by OCaml is correct (if not we just assert, it's an internal error).
(It didn't even compile before, so we know it was never used).
(cherry picked from commit bcd6b3ec3a1038d840e832732b3910f939566436)
(cherry picked from commit 1b64c54b8a7f3a0ada0cc52fc74d800a55318112)
---
generator/daemon.ml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/generator/daemon.ml b/generator/daemon.ml
index 0218d3e5..d9f22c51 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -611,6 +611,7 @@ let generate_daemon_caml_stubs () =
#include <string.h>
#include <inttypes.h>
#include <errno.h>
+#include <assert.h>
#include <caml/alloc.h>
#include <caml/callback.h>
@@ -646,9 +647,12 @@ let generate_daemon_caml_stubs () =
fun i ->
pr " v = Field (retv, %d);\n" i;
function
- | n, (FString|FDevice|FUUID) ->
+ | n, (FString|FDevice) ->
pr " ret->%s = strdup (String_val (v));\n" n;
pr " if (ret->%s == NULL) return NULL;\n" n
+ | n, FUUID ->
+ pr " assert (caml_string_length (v) == sizeof ret->%s);\n" n;
+ pr " memcpy (ret->%s, String_val (v), sizeof ret->%s);\n" n n
| n, FBuffer ->
pr " ret->%s_len = caml_string_length (v);\n" n;
pr " ret->%s = strdup (String_val (v));\n" n;

View File

@ -0,0 +1,44 @@
From e0798c2658a1f9f44380224b93de7e42869b3a3b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 21:31:49 +0100
Subject: [PATCH] Update common submodule
Richard W.M. Jones (1):
mlstdutils: Implement String.implode
(cherry picked from commit c7930f21405720f51d74efa9f6f7b9da0132a929)
---
common | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Submodule common 93a7f3af..9c178a92:
diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
index 86b21a7c..1177ff69 100644
--- a/common/mlstdutils/std_utils.ml
+++ b/common/mlstdutils/std_utils.ml
@@ -256,6 +256,12 @@ module String = struct
let map_chars f str =
List.map f (explode str)
+ let implode cs =
+ let n = List.length cs in
+ let b = Bytes.create n in
+ List.iteri (Bytes.unsafe_set b) cs;
+ Bytes.to_string b
+
let spaces n = String.make n ' '
let span str accept =
diff --git a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
index a39ac5f3..6811b4bc 100644
--- a/common/mlstdutils/std_utils.mli
+++ b/common/mlstdutils/std_utils.mli
@@ -123,6 +123,8 @@ module String : sig
(** Explode a string into a list of characters. *)
val map_chars : (char -> 'a) -> string -> 'a list
(** Explode string, then map function over the characters. *)
+ val implode : char list -> string
+ (** Join list of characters into a single string. *)
val spaces : int -> string
(** [spaces n] creates a string of n spaces. *)
val span : string -> string -> int

View File

@ -0,0 +1,660 @@
From c34a91bb2301d2ba61849126c9d365760ff7bf5f Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 10:41:59 +0100
Subject: [PATCH] daemon: Rewrite {pvs,vgs,lvs}-full APIs in OCaml
These were previously written in very convoluted C which had to deal
with parsing the crazy output of the "lvm" command. In fact the
parsing was so complex that it was generated by the generator. It's
easier to do this in OCaml.
These are basically legacy APIs. They cannot be expanded and LVM
already supports many more fields. We should replace these with APIs
for getting single named fields from LVM.
(cherry picked from commit a73f248369d35249a9324a0e0df9f7ccd1420d3f)
(cherry picked from commit 80b2fcb243613bc16217b5908941ed2607f398fd)
---
.gitignore | 2 +-
daemon/Makefile.am | 5 +-
daemon/lvm.c | 22 ----
daemon/lvm_full.ml | 221 ++++++++++++++++++++++++++++++++++++++
docs/C_SOURCE_FILES | 1 -
generator/actions_core.ml | 3 +
generator/daemon.ml | 190 --------------------------------
generator/daemon.mli | 1 -
generator/main.ml | 2 -
generator/structs.ml | 4 +-
generator/structs.mli | 7 --
po/POTFILES | 1 -
12 files changed, 229 insertions(+), 230 deletions(-)
create mode 100644 daemon/lvm_full.ml
diff --git a/.gitignore b/.gitignore
index 73a561c2..f58f909d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,7 +97,7 @@ Makefile.in
/daemon/listfs.mli
/daemon/lvm.mli
/daemon/lvm_dm.mli
-/daemon/lvm-tokenization.c
+/daemon/lvm_full.mli
/daemon/md.mli
/daemon/mount.mli
/daemon/names.c
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 7109e114..409c5ca7 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -22,7 +22,6 @@ BUILT_SOURCES = \
caml-stubs.c \
dispatch.c \
names.c \
- lvm-tokenization.c \
structs-cleanups.c \
structs-cleanups.h \
stubs-0.c \
@@ -52,6 +51,7 @@ generator_built = \
listfs.mli \
lvm.mli \
lvm_dm.mli \
+ lvm_full.mli \
md.mli \
mount.mli \
optgroups.ml \
@@ -151,7 +151,6 @@ guestfsd_SOURCES = \
luks.c \
lvm.c \
lvm-filter.c \
- lvm-tokenization.c \
md.c \
mkfs.c \
mknod.c \
@@ -296,6 +295,7 @@ SOURCES_MLI = \
listfs.mli \
lvm.mli \
lvm_dm.mli \
+ lvm_full.mli \
lvm_utils.mli \
md.mli \
mount.mli \
@@ -329,6 +329,7 @@ SOURCES_ML = \
ldm.ml \
link.ml \
lvm.ml \
+ lvm_full.ml \
lvm_utils.ml \
lvm_dm.ml \
findfs.ml \
diff --git a/daemon/lvm.c b/daemon/lvm.c
index 7e76e17c..001aacb2 100644
--- a/daemon/lvm.c
+++ b/daemon/lvm.c
@@ -139,28 +139,6 @@ do_vgs (void)
return convert_lvm_output (out, NULL);
}
-/* These were so complex to implement that I ended up auto-generating
- * the code. That code is in stubs.c, and it is generated as usual
- * by generator.ml.
- */
-guestfs_int_lvm_pv_list *
-do_pvs_full (void)
-{
- return parse_command_line_pvs ();
-}
-
-guestfs_int_lvm_vg_list *
-do_vgs_full (void)
-{
- return parse_command_line_vgs ();
-}
-
-guestfs_int_lvm_lv_list *
-do_lvs_full (void)
-{
- return parse_command_line_lvs ();
-}
-
int
do_pvcreate (const char *device)
{
diff --git a/daemon/lvm_full.ml b/daemon/lvm_full.ml
new file mode 100644
index 00000000..d5653d2f
--- /dev/null
+++ b/daemon/lvm_full.ml
@@ -0,0 +1,221 @@
+(* guestfs-inspection
+ * Copyright (C) 2009-2025 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.
+ *)
+
+(* This file implements the complicated lvs-full, vgs-full and pvs-full APIs
+ *
+ * XXX Deprecate these APIs are replace with APIs for getting single
+ * named fields from LVM. That will be slower but far more flexible
+ * and extensible.
+ *)
+
+open Unix
+open Printf
+
+open Std_utils
+
+open Utils
+
+(* LVM UUIDs are basically 32 byte strings with '-' inserted.
+ * Remove the '-' characters and check it's the right length.
+ *)
+let parse_uuid uuid =
+ let uuid' =
+ uuid |> String.explode |> List.filter ((<>) '-') |> String.implode in
+ if String.length uuid' <> 32 then
+ failwithf "lvm-full: parse_uuid: unexpected UUID format: %S" uuid;
+ uuid'
+
+(* Parse the percent fields. These can be empty. *)
+let parse_percent pc = if pc = "" then None else Some (float_of_string pc)
+
+(* XXX These must match generator/structs.ml *)
+let lvm_pv_cols = [
+ "pv_name"; (* FString *)
+ "pv_uuid"; (* FUUID *)
+ "pv_fmt"; (* FString *)
+ "pv_size"; (* FBytes *)
+ "dev_size"; (* FBytes *)
+ "pv_free"; (* FBytes *)
+ "pv_used"; (* FBytes *)
+ "pv_attr"; (* FString (* XXX *) *)
+ "pv_pe_count"; (* FInt64 *)
+ "pv_pe_alloc_count"; (* FInt64 *)
+ "pv_tags"; (* FString *)
+ "pe_start"; (* FBytes *)
+ "pv_mda_count"; (* FInt64 *)
+ "pv_mda_free"; (* FBytes *)
+]
+
+let tokenize_pvs = function
+ | [ pv_name; pv_uuid; pv_fmt; pv_size; dev_size; pv_free;
+ pv_used; pv_attr; pv_pe_count; pv_pe_alloc_count; pv_tags;
+ pe_start; pv_mda_count; pv_mda_free ] ->
+ { Structs.pv_name = pv_name;
+ pv_uuid = parse_uuid pv_uuid;
+ pv_fmt = pv_fmt;
+ pv_size = Int64.of_string pv_size;
+ dev_size = Int64.of_string dev_size;
+ pv_free = Int64.of_string pv_free;
+ pv_used = Int64.of_string pv_used;
+ pv_attr = pv_attr;
+ pv_pe_count = Int64.of_string pv_pe_count;
+ pv_pe_alloc_count = Int64.of_string pv_pe_alloc_count;
+ pv_tags = pv_tags;
+ pe_start = Int64.of_string pe_start;
+ pv_mda_count = Int64.of_string pv_mda_count;
+ pv_mda_free = Int64.of_string pv_mda_free }
+
+ | fields ->
+ failwithf "pvs-full: tokenize_pvs: unexpected number of fields: %d"
+ (List.length fields)
+
+(* XXX These must match generator/structs.ml *)
+let lvm_vg_cols = [
+ "vg_name"; (* FString *)
+ "vg_uuid"; (* FUUID *)
+ "vg_fmt"; (* FString *)
+ "vg_attr"; (* FString (* XXX *) *)
+ "vg_size"; (* FBytes *)
+ "vg_free"; (* FBytes *)
+ "vg_sysid"; (* FString *)
+ "vg_extent_size"; (* FBytes *)
+ "vg_extent_count"; (* FInt64 *)
+ "vg_free_count"; (* FInt64 *)
+ "max_lv"; (* FInt64 *)
+ "max_pv"; (* FInt64 *)
+ "pv_count"; (* FInt64 *)
+ "lv_count"; (* FInt64 *)
+ "snap_count"; (* FInt64 *)
+ "vg_seqno"; (* FInt64 *)
+ "vg_tags"; (* FString *)
+ "vg_mda_count"; (* FInt64 *)
+ "vg_mda_free"; (* FBytes *)
+]
+
+let tokenize_vgs = function
+ | [ vg_name; vg_uuid; vg_fmt; vg_attr; vg_size; vg_free; vg_sysid;
+ vg_extent_size; vg_extent_count; vg_free_count; max_lv;
+ max_pv; pv_count; lv_count; snap_count; vg_seqno; vg_tags;
+ vg_mda_count; vg_mda_free ] ->
+ { Structs.vg_name = vg_name;
+ vg_uuid = parse_uuid vg_uuid;
+ vg_fmt = vg_fmt;
+ vg_attr = vg_attr;
+ vg_size = Int64.of_string vg_size;
+ vg_free = Int64.of_string vg_free;
+ vg_sysid = vg_sysid;
+ vg_extent_size = Int64.of_string vg_extent_size;
+ vg_extent_count = Int64.of_string vg_extent_count;
+ vg_free_count = Int64.of_string vg_free_count;
+ max_lv = Int64.of_string max_lv;
+ max_pv = Int64.of_string max_pv;
+ pv_count = Int64.of_string pv_count;
+ lv_count = Int64.of_string lv_count;
+ snap_count = Int64.of_string snap_count;
+ vg_seqno = Int64.of_string vg_seqno;
+ vg_tags = vg_tags;
+ vg_mda_count = Int64.of_string vg_mda_count;
+ vg_mda_free = Int64.of_string vg_mda_free }
+
+ | fields ->
+ failwithf "pvs-full: tokenize_vgs: unexpected number of fields: %d"
+ (List.length fields)
+
+(* XXX These must match generator/structs.ml *)
+let lvm_lv_cols = [
+ "lv_name"; (* FString *)
+ "lv_uuid"; (* FUUID *)
+ "lv_attr"; (* FString (* XXX *) *)
+ "lv_major"; (* FInt64 *)
+ "lv_minor"; (* FInt64 *)
+ "lv_kernel_major"; (* FInt64 *)
+ "lv_kernel_minor"; (* FInt64 *)
+ "lv_size"; (* FBytes *)
+ "seg_count"; (* FInt64 *)
+ "origin"; (* FString *)
+ "snap_percent"; (* FOptPercent *)
+ "copy_percent"; (* FOptPercent *)
+ "move_pv"; (* FString *)
+ "lv_tags"; (* FString *)
+ "mirror_log"; (* FString *)
+ "modules"; (* FString *)
+]
+
+let tokenize_lvs = function
+ | [ lv_name; lv_uuid; lv_attr; lv_major; lv_minor; lv_kernel_major;
+ lv_kernel_minor; lv_size; seg_count; origin; snap_percent;
+ copy_percent; move_pv; lv_tags; mirror_log; modules ] ->
+ { Structs.lv_name = lv_name;
+ lv_uuid = parse_uuid lv_uuid;
+ lv_attr = lv_attr;
+ lv_major = Int64.of_string lv_major;
+ lv_minor = Int64.of_string lv_minor;
+ lv_kernel_major = Int64.of_string lv_kernel_major;
+ lv_kernel_minor = Int64.of_string lv_kernel_minor;
+ lv_size = Int64.of_string lv_size;
+ seg_count = Int64.of_string seg_count;
+ origin = origin;
+ snap_percent = parse_percent snap_percent;
+ copy_percent = parse_percent copy_percent;
+ move_pv = move_pv;
+ lv_tags = lv_tags;
+ mirror_log = mirror_log;
+ modules = modules }
+
+ | fields ->
+ failwithf "pvs-full: tokenize_vgs: unexpected number of fields: %d"
+ (List.length fields)
+
+let rec pvs_full () =
+ let out = run_lvm_command "pvs" lvm_pv_cols in
+ let lines = trim_and_split out in
+ let pvs = List.map tokenize_pvs lines in
+ pvs
+
+and vgs_full () =
+ let out = run_lvm_command "vgs" lvm_vg_cols in
+ let lines = trim_and_split out in
+ let vgs = List.map tokenize_vgs lines in
+ vgs
+
+and lvs_full () =
+ let out = run_lvm_command "lvs" lvm_lv_cols in
+ let lines = trim_and_split out in
+ let lvs = List.map tokenize_lvs lines in
+ lvs
+
+and run_lvm_command typ cols =
+ let cols = String.concat "," cols in
+ let cmd = [ typ; "-o"; cols;
+ "--unbuffered"; "--noheadings"; "--nosuffix";
+ "--separator"; "\r"; "--units"; "b" ] in
+ command "lvm" cmd
+
+and trim_and_split out =
+ (* Split the output into lines. *)
+ let lines = String.nsplit "\n" out in
+
+ (* LVM puts leading whitespace on each line so remove that. *)
+ let lines = List.map String.triml lines in
+
+ (* Ignore any blank lines. *)
+ let lines = List.filter ((<>) "") lines in
+
+ (* Split each line into fields. *)
+ let lines = List.map (String.nsplit "\r") lines in
+ lines
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index 0038f95e..cdfb1d61 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -111,7 +111,6 @@ daemon/link.c
daemon/ls.c
daemon/luks.c
daemon/lvm-filter.c
-daemon/lvm-tokenization.c
daemon/lvm.c
daemon/md.c
daemon/mkfs.c
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index 60c4b577..32dd47c7 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -1767,6 +1767,7 @@ See also C<guestfs_lvs_full>, C<guestfs_list_filesystems>." };
{ defaults with
name = "pvs_full"; added = (0, 0, 4);
style = RStructList ("physvols", "lvm_pv"), [], [];
+ impl = OCaml "Lvm_full.pvs_full";
optional = Some "lvm2";
shortdesc = "list the LVM physical volumes (PVs)";
longdesc = "\
@@ -1776,6 +1777,7 @@ of the L<pvs(8)> command. The \"full\" version includes all fields." };
{ defaults with
name = "vgs_full"; added = (0, 0, 4);
style = RStructList ("volgroups", "lvm_vg"), [], [];
+ impl = OCaml "Lvm_full.vgs_full";
optional = Some "lvm2";
shortdesc = "list the LVM volume groups (VGs)";
longdesc = "\
@@ -1785,6 +1787,7 @@ of the L<vgs(8)> command. The \"full\" version includes all fields." };
{ defaults with
name = "lvs_full"; added = (0, 0, 4);
style = RStructList ("logvols", "lvm_lv"), [], [];
+ impl = OCaml "Lvm_full.lvs_full";
optional = Some "lvm2";
shortdesc = "list the LVM logical volumes (LVs)";
longdesc = "\
diff --git a/generator/daemon.ml b/generator/daemon.ml
index d9f22c51..25be2bef 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -956,196 +956,6 @@ let generate_daemon_dispatch () =
pr "}\n";
pr "\n"
-let generate_daemon_lvm_tokenization () =
- generate_header CStyle GPLv2plus;
-
- pr "\
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-
-#include \"daemon.h\"
-#include \"c-ctype.h\"
-#include \"guestfs_protocol.h\"
-#include \"actions.h\"
-#include \"optgroups.h\"
-
-";
-
- (* LVM columns and tokenization functions. *)
- (* XXX This generates crap code. We should rethink how we
- * do this parsing.
- *)
- List.iter (
- function
- | typ, cols ->
- pr "static const char lvm_%s_cols[] = \"%s\";\n"
- typ (String.concat "," (List.map fst cols));
- pr "\n";
-
- pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
- pr "{\n";
- pr " char *tok, *p, *next;\n";
- pr " size_t i, j;\n";
- pr "\n";
- (*
- pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
- pr "\n";
- *)
- pr " if (!str) {\n";
- pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
- pr " return -1;\n";
- pr " }\n";
- pr " if (!*str || c_isspace (*str)) {\n";
- pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
- pr " return -1;\n";
- pr " }\n";
- pr " tok = str;\n";
- List.iter (
- fun (name, coltype) ->
- pr " if (!tok) {\n";
- 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, '\\r');\n";
- pr " if (*p) next = p+1; else next = NULL;\n";
- pr " *p = '\\0';\n";
- (match coltype with
- | FString | FDevice ->
- pr " r->%s = strdup (tok);\n" name;
- pr " if (r->%s == NULL) {\n" name;
- pr " perror (\"strdup\");\n";
- pr " return -1;\n";
- pr " }\n"
- | FUUID ->
- pr " for (i = j = 0; i < 32; ++j) {\n";
- pr " if (tok[j] == '\\0') {\n";
- pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
- pr " return -1;\n";
- pr " } else if (tok[j] != '-')\n";
- pr " r->%s[i++] = tok[j];\n" name;
- pr " }\n";
- | FBytes ->
- pr " if (sscanf (tok, \"%%\" SCNi64, &r->%s) != 1) {\n" name;
- pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
- pr " return -1;\n";
- pr " }\n";
- | FInt64 ->
- pr " if (sscanf (tok, \"%%\" SCNi64, &r->%s) != 1) {\n" name;
- pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
- pr " return -1;\n";
- pr " }\n";
- | FOptPercent ->
- pr " if (tok[0] == '\\0')\n";
- pr " r->%s = -1;\n" name;
- pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
- pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
- pr " return -1;\n";
- pr " }\n";
- | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
- assert false (* can never be an LVM column *)
- );
- pr " tok = next;\n";
- ) cols;
-
- pr " if (tok != NULL) {\n";
- pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
- pr " return -1;\n";
- pr " }\n";
- pr " return 0;\n";
- pr "}\n";
- pr "\n";
-
- pr "guestfs_int_lvm_%s_list *\n" typ;
- pr "parse_command_line_%ss (void)\n" typ;
- pr "{\n";
- pr " char *out, *err;\n";
- pr " char *p, *pend;\n";
- pr " int r, i;\n";
- pr " guestfs_int_lvm_%s_list *ret;\n" typ;
- pr " void *newp;\n";
- pr "\n";
- pr " ret = malloc (sizeof *ret);\n";
- pr " if (!ret) {\n";
- pr " reply_with_perror (\"malloc\");\n";
- pr " return NULL;\n";
- pr " }\n";
- pr "\n";
- pr " ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
- pr " ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
- pr "\n";
- pr " r = command (&out, &err,\n";
- pr " \"lvm\", \"%ss\",\n" typ;
- pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
- pr " \"--nosuffix\", \"--separator\", \"\\r\", \"--units\", \"b\", NULL);\n";
- pr " if (r == -1) {\n";
- pr " reply_with_error (\"%%s\", err);\n";
- pr " free (out);\n";
- pr " free (err);\n";
- pr " free (ret);\n";
- pr " return NULL;\n";
- pr " }\n";
- pr "\n";
- pr " free (err);\n";
- pr "\n";
- pr " /* Tokenize each line of the output. */\n";
- pr " p = out;\n";
- pr " i = 0;\n";
- pr " while (p) {\n";
- pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
- pr " if (pend) {\n";
- pr " *pend = '\\0';\n";
- pr " pend++;\n";
- pr " }\n";
- pr "\n";
- pr " while (*p && c_isspace (*p)) /* Skip any leading whitespace. */\n";
- pr " p++;\n";
- pr "\n";
- pr " if (!*p) { /* Empty line? Skip it. */\n";
- pr " p = pend;\n";
- pr " continue;\n";
- pr " }\n";
- pr "\n";
- pr " /* Allocate some space to store this next entry. */\n";
- pr " newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
- pr " sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
- pr " if (newp == NULL) {\n";
- pr " reply_with_perror (\"realloc\");\n";
- pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
- pr " free (ret);\n";
- pr " free (out);\n";
- pr " return NULL;\n";
- pr " }\n";
- pr " ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
- pr "\n";
- pr " /* Tokenize the next entry. */\n";
- pr " r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
- pr " if (r == -1) {\n";
- pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
- pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
- pr " free (ret);\n";
- pr " free (out);\n";
- pr " return NULL;\n";
- pr " }\n";
- pr "\n";
- pr " ++i;\n";
- pr " p = pend;\n";
- pr " }\n";
- pr "\n";
- pr " ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
- pr "\n";
- pr " free (out);\n";
- pr " return ret;\n";
- pr "}\n"
-
- ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
-
(* Generate a list of function names, for debugging in the daemon.. *)
let generate_daemon_names () =
generate_header CStyle GPLv2plus;
diff --git a/generator/daemon.mli b/generator/daemon.mli
index edf331a9..77c6e632 100644
--- a/generator/daemon.mli
+++ b/generator/daemon.mli
@@ -23,7 +23,6 @@ val generate_daemon_caml_stubs : unit -> unit
val generate_daemon_caml_callbacks_ml : unit -> unit
val generate_daemon_caml_interface : string -> unit -> unit
val generate_daemon_dispatch : unit -> unit
-val generate_daemon_lvm_tokenization : unit -> unit
val generate_daemon_names : unit -> unit
val generate_daemon_optgroups_c : unit -> unit
val generate_daemon_optgroups_h : unit -> unit
diff --git a/generator/main.ml b/generator/main.ml
index e124047e..18afd3bb 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -147,8 +147,6 @@ Run it from the top source directory using the command
Daemon.generate_daemon_optgroups_ml;
output_to "daemon/optgroups.mli"
Daemon.generate_daemon_optgroups_mli;
- output_to "daemon/lvm-tokenization.c"
- Daemon.generate_daemon_lvm_tokenization;
output_to "daemon/structs-cleanups.c"
Daemon.generate_daemon_structs_cleanups_c;
output_to "daemon/structs-cleanups.h"
diff --git a/generator/structs.ml b/generator/structs.ml
index 93a3ed03..239a5d5e 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -31,9 +31,7 @@ type struc = {
s_unused : unit; (* Silences warning 23 when using 'defaults with ...' *)
}
-(* Because we generate extra parsing code for LVM command line tools,
- * we have to pull out the LVM columns separately here.
- *)
+(* XXX These must match daemon/lvm_full.ml *)
let lvm_pv_cols = [
"pv_name", FDevice;
"pv_uuid", FUUID;
diff --git a/generator/structs.mli b/generator/structs.mli
index e7a29b01..b3444623 100644
--- a/generator/structs.mli
+++ b/generator/structs.mli
@@ -34,13 +34,6 @@ type struc = {
val structs : struc list
(** List of structures. *)
-val lvm_pv_cols : cols
-val lvm_vg_cols : cols
-val lvm_lv_cols : cols
-(** These are exported to the daemon code generator where they are
- used to generate code for parsing the output of commands like
- [lvs]. One day replace this with liblvm API calls. *)
-
val lookup_struct : string -> struc
(** Lookup a struct by name. *)
diff --git a/po/POTFILES b/po/POTFILES
index 75b040c0..d10f9710 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -90,7 +90,6 @@ daemon/link.c
daemon/ls.c
daemon/luks.c
daemon/lvm-filter.c
-daemon/lvm-tokenization.c
daemon/lvm.c
daemon/md.c
daemon/mkfs.c

View File

@ -0,0 +1,71 @@
From 2f529e9a07eb351510a880a4256111014bcf9235 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 16 Apr 2025 10:27:25 +0100
Subject: [PATCH] daemon: inspect: Resolve Ubuntu 22+
/dev/disk/by-id/dm-uuid-LVM-... in fstab
Linux + LVM supports device names like /dev/disk/by-id/dm-uuid-LVM-
followed by two concatenated UUIDs, firstly for the volume group and
secondly for the logical volume. We can reverse those to get the
device name (/dev/VG/LV).
fstab entries look like:
# / was on /dev/vg0/lv-0 during curtin installation
/dev/disk/by-id/dm-uuid-LVM-OzFWT6NHkstr1hcmrWRRMDGPn9xdZj1YOOycQ533186x288FdU6UubU3OlnWJz6D / ext4 defaults 0 1
# /usr was on /dev/vg0/lv-1 during curtin installation
/dev/disk/by-id/dm-uuid-LVM-OzFWT6NHkstr1hcmrWRRMDGPn9xdZj1YZu53m4ZssZ8Jeb3I14RAJwIj5YlHIb9P /usr ext4 defaults 0 1
The upshot of this fix is that we are now able to correctly inspect
and run virt-v2v on Ubuntu 22+ guests with split /usr. In particular,
we correctly map /etc/fstab entries like the above to LV device names,
which means that /usr merging now works correctly.
Reported-by: Jaroslav Spanko
Thanks: Daniel Berrange
Fixes: https://issues.redhat.com/browse/RHEL-87493
(cherry picked from commit e43ca1912973b3ddfa73b09a4690aa8bb26e08af)
(cherry picked from commit 180293338e0d127d0545fe03b6141ed04e22e441)
---
daemon/inspect_fs_unix_fstab.ml | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/daemon/inspect_fs_unix_fstab.ml b/daemon/inspect_fs_unix_fstab.ml
index 45c62175..dcbdab3c 100644
--- a/daemon/inspect_fs_unix_fstab.ml
+++ b/daemon/inspect_fs_unix_fstab.ml
@@ -27,6 +27,7 @@ open Inspect_utils
let re_cciss = PCRE.compile "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$"
let re_diskbyid = PCRE.compile "^/dev/disk/by-id/.*-part(\\d+)$"
+let re_dmuuid = PCRE.compile "^/dev/disk/by-id/dm-uuid-LVM-([0-9a-zA-Z]{32})([0-9a-zA-Z]{32})$"
let re_freebsd_gpt = PCRE.compile "^/dev/(ada{0,1}|vtbd)(\\d+)p(\\d+)$"
let re_freebsd_mbr = PCRE.compile "^/dev/(ada{0,1}|vtbd)(\\d+)s(\\d+)([a-z])$"
let re_hurd_dev = PCRE.compile "^/dev/(h)d(\\d+)s(\\d+)$"
@@ -407,6 +408,26 @@ and resolve_fstab_device spec md_map os_type =
Failure _ -> default
)
+ (* Ubuntu 22+ uses /dev/disk/by-id/dm-uuid-LVM-... followed by a
+ * double UUID which identifies an LV. The first part of the UUID
+ * is the VG UUID. The second part is the LV UUID.
+ *)
+ else if PCRE.matches re_dmuuid spec then (
+ debug_matching "dmuuid";
+ let vg_uuid_spec = PCRE.sub 1 and lv_uuid_spec = PCRE.sub 2 in
+ try
+ (* Get the list of all VGs and LVs. *)
+ let vgs = Lvm_full.vgs_full () and lvs = Lvm_full.lvs_full () in
+ (* Find one VG & LV (hopefully) that matches the UUIDs. *)
+ let vg =
+ List.find (fun { Structs.vg_uuid } -> vg_uuid = vg_uuid_spec) vgs
+ and lv =
+ List.find (fun { Structs.lv_uuid } -> lv_uuid = lv_uuid_spec) lvs in
+ Mountable.of_device (sprintf "/dev/%s/%s" vg.vg_name lv.lv_name)
+ with
+ Failure _ | Not_found -> default
+ )
+
else if PCRE.matches re_freebsd_gpt spec then (
debug_matching "FreeBSD GPT";
(* group 1 (type) is not used *)

View File

@ -0,0 +1,39 @@
From 39e25217dccb4b49f2ab481f0b026f1498973647 Mon Sep 17 00:00:00 2001
From: Darren Archibald <darren.archibald@oracle.com>
Date: Mon, 3 Oct 2022 09:55:14 -0700
Subject: [PATCH] Add Oracle Linux identifier
Signed-off-by: Darren Archibald <darren.archibald@oracle.com>
---
daemon/inspect_fs_unix.ml | 1 +
m4/guestfs-appliance.m4 | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemon/inspect_fs_unix.ml b/daemon/inspect_fs_unix.ml
index d8dce60..ee89ff0 100644
--- a/daemon/inspect_fs_unix.ml
+++ b/daemon/inspect_fs_unix.ml
@@ -159,6 +159,7 @@ and distro_of_os_release_id = function
| "pardus" -> Some DISTRO_PARDUS
| "pld" -> Some DISTRO_PLD_LINUX
| "rhel" -> Some DISTRO_RHEL
+ | "ol" -> Some DISTRO_ORACLE_LINUX
| "rocky" -> Some DISTRO_ROCKY
| "sles" | "sled" -> Some DISTRO_SLES
| "ubuntu" -> Some DISTRO_UBUNTU
diff --git a/m4/guestfs-appliance.m4 b/m4/guestfs-appliance.m4
index 4e671d2..dc06d1a 100644
--- a/m4/guestfs-appliance.m4
+++ b/m4/guestfs-appliance.m4
@@ -114,7 +114,7 @@ if test "x$ENABLE_APPLIANCE" = "xyes"; then
fi ) | tr '@<:@:lower:@:>@' '@<:@:upper:@:>@'
)"
AS_CASE([$DISTRO],
- [FEDORA | RHEL | CENTOS | ALMALINUX | CLOUDLINUX \
+ [FEDORA | RHEL | OL | CENTOS | ALMALINUX | CLOUDLINUX \
| ROCKY | VIRTUOZZO],
[DISTRO=REDHAT],
[OPENSUSE* | SLED | SLES],[DISTRO=SUSE],
--
2.39.3

0
SOURCES/copy-patches.sh Executable file → Normal file
View File

View File

@ -45,7 +45,7 @@ Summary: Access and modify virtual machine disk images
Name: libguestfs
Epoch: 1
Version: 1.50.2
Release: 2%{?dist}
Release: 3.0.1%{?dist}
License: LGPLv2+
# Build only for architectures that have a kernel
@ -130,6 +130,17 @@ Patch0036: 0036-Update-common-submodule.patch
Patch0037: 0037-New-APIs-findfs_partuuid-and-findfs_partlabel.patch
Patch0038: 0038-inspection-Resolve-PARTUUID-and-PARTLABEL-in-etc-fst.patch
Patch0039: 0039-daemon-New-command_out-and-sh_out-APIs.patch
Patch0040: 0040-lib-Print-kernel-utsname-in-debug-output.patch
Patch0041: 0041-daemon-inspect-Add-some-debugging-of-usr-merging.patch
Patch0042: 0042-generator-Implement-struct-FDevice-type.patch
Patch0043: 0043-generator-Use-new-FDevice-type-for-the-pvs-full-pv_n.patch
Patch0044: 0044-daemon-inspect-Resolve-Ubuntu-22-dev-disk-by-uuid-in.patch
Patch0045: 0045-generator-Fix-implementation-of-FUUID-for-OCaml-func.patch
Patch0046: 0046-Update-common-submodule.patch
Patch0047: 0047-daemon-Rewrite-pvs-vgs-lvs-full-APIs-in-OCaml.patch
Patch0048: 0048-daemon-inspect-Resolve-Ubuntu-22-dev-disk-by-id-dm-u.patch
Patch1000: 1000-Add-Oracle-Linux-identifier.patch
%if 0%{patches_touch_autotools}
BuildRequires: autoconf, automake, libtool, gettext-devel
@ -245,9 +256,7 @@ BuildRequires: attr
BuildRequires: augeas-libs
BuildRequires: bash
BuildRequires: binutils
%if !0%{?rhel}
BuildRequires: btrfs-progs
%endif
BuildRequires: bzip2
BuildRequires: clevis-luks
BuildRequires: coreutils
@ -578,7 +587,7 @@ guests. Install this package if you want libguestfs to be able to
inspect non-Linux guests and display icons from them.
The only reason this is a separate package is to avoid core libguestfs
having to depend on Perl. See https://bugzilla.redhat.com/1194158
having to depend on Perl.
%package bash-completion
@ -797,6 +806,7 @@ fi
%endif
--without-java \
--disable-erlang \
--with-extra-packages="btrfs-progs" \
$extra
# 'INSTALLDIRS' ensures that Perl and Ruby libs are installed in the
@ -1146,6 +1156,16 @@ rm ocaml/html/.gitignore
%changelog
* Wed Apr 30 2025 EL Errata <el-errata_ww@oracle.com> - 1.50.2-3.0.1
- Add btrfs-progs to the packages installed in the appliance [Orabug: 34137448]
- Replace upstream references from a description tag
- Fix build on Oracle Linux [Orabug: 29319324]
- Set DISTRO_ORACLE_LINUX correspeonding to ol
* Tue Apr 29 2025 Richard W.M. Jones <rjones@redhat.com> - 1:1.50.2-3
- Fix virt-v2v conversion of split /usr Ubuntu 22+
resolves: RHEL-88803
* Thu Feb 27 2025 Richard W.M. Jones <rjones@redhat.com> - 1:1.50.2-2
- Add new APIs to allow command output > 4MB
resolves: RHEL-81095