660 lines
23 KiB
Diff
660 lines
23 KiB
Diff
From 80b2fcb243613bc16217b5908941ed2607f398fd 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)
|
|
---
|
|
.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 68b27c79..c5e8f802 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 bb72c024..90ece846 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 \
|
|
@@ -152,7 +152,6 @@ guestfsd_SOURCES = \
|
|
luks.c \
|
|
lvm.c \
|
|
lvm-filter.c \
|
|
- lvm-tokenization.c \
|
|
md.c \
|
|
mkfs.c \
|
|
mknod.c \
|
|
@@ -298,6 +297,7 @@ SOURCES_MLI = \
|
|
listfs.mli \
|
|
lvm.mli \
|
|
lvm_dm.mli \
|
|
+ lvm_full.mli \
|
|
lvm_utils.mli \
|
|
md.mli \
|
|
mount.mli \
|
|
@@ -333,6 +333,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 eb047b6b..01991dd0 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 91decf40..f9b77a18 100644
|
|
--- a/generator/daemon.ml
|
|
+++ b/generator/daemon.ml
|
|
@@ -951,196 +951,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 ff5e964a..6e36d9c7 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
|