These are a prelude to fixing https://bugzilla.redhat.com/show_bug.cgi?id=1590220 A lot of the virt-p2v configuration code was duplicated manually. These changes make sure that most of it is generated. Rich.
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 1/3] p2v: Generate config struct and p2v/config.c.
Mostly refactoring to make it easier to add fields to this struct in
future.
I'd like to call the header p2v/config.h but that's not possible since
it conflicts with the autoconf-generated file.
---
.gitignore | 2 +
generator/Makefile.am | 3 +
generator/main.ml | 5 +
generator/p2v_config.ml | 389 +++++++++++++++++++++++++++++++++++
generator/p2v_config.mli | 20 ++
p2v/Makefile.am | 5 +-
p2v/config.c | 208 -------------------
p2v/p2v.h | 56 +----
p2v/test-virt-p2v-cmdline.sh | 14 +-
9 files changed, 431 insertions(+), 271 deletions(-)
diff --git a/.gitignore b/.gitignore
index d25089677..4c0ff4e1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -430,10 +430,12 @@ Makefile.in
/ocaml/t/*.bc
/ocaml/t/*.opt
/p2v/about-authors.c
+/p2v/config.c
/p2v/dependencies.archlinux
/p2v/dependencies.debian
/p2v/dependencies.redhat
/p2v/dependencies.suse
+/p2v/p2v-config.h
/p2v/stamp-test-virt-p2v-pxe-data-files
/p2v/stamp-test-virt-p2v-pxe-hostkey
/p2v/stamp-test-virt-p2v-pxe-kernel
diff --git a/generator/Makefile.am b/generator/Makefile.am
index c2d10966a..d026e9558 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -101,6 +101,8 @@ sources = \
proc_nr.mli \
python.ml \
python.mli \
+ p2v_config.ml \
+ p2v_config.mli \
ruby.ml \
ruby.mli \
structs.ml \
@@ -165,6 +167,7 @@ objects = \
errnostring.cmo \
customize.cmo \
UEFI.cmo \
+ p2v_config.cmo \
main.cmo
EXTRA_DIST = $(sources) files-generated.txt
diff --git a/generator/main.ml b/generator/main.ml
index e51313779..ecc551f72 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -363,6 +363,11 @@ Run it from the top source directory using the command
output_to "customize/customize-options.pod"
Customize.generate_customize_options_pod;
+ output_to "p2v/p2v-config.h"
+ P2v_config.generate_p2v_config_h;
+ output_to "p2v/config.c"
+ P2v_config.generate_p2v_config_c;
+
(* Generate the list of files generated -- last. *)
printf "generated %d lines of code\n" (get_lines_generated ());
let files = List.sort compare (get_files_generated ()) in
diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml
new file mode 100644
index 000000000..1f998fd7c
--- /dev/null
+++ b/generator/p2v_config.ml
@@ -0,0 +1,389 @@
+(* libguestfs
+ * Copyright (C) 2018 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
+ *)
+
+(* Please read generator/README first. *)
+
+open Printf
+
+open Std_utils
+open Docstrings
+open Pr
+
+let generate_header = generate_header
~inputs:["generator/p2v_config.ml"]
+
+type enum_choice = string * string (* name, comment *)
+type enum = string * enum_choice list
+
+type config_entry + | ConfigString of string
+ | ConfigInt of string * int (* field name, initial value *)
+ | ConfigUnsigned of string
+ | ConfigUInt64 of string
+ | ConfigEnum of string
+ | ConfigBool of string
+ | ConfigStringList of string
+ | ConfigSection of string * config_entry list
+
+(* Enums. *)
+let enums = [
+ "basis", [
+ "BASIS_UNKNOWN", "RTC could not be read";
+ "BASIS_UTC", "RTC is either UTC or an offset from
UTC";
+ "BASIS_LOCALTIME", "RTC is localtime";
+ ];
+ "output_allocation", [
+ "OUTPUT_ALLOCATION_NONE", "output allocation not
set";
+ "OUTPUT_ALLOCATION_SPARSE", "sparse";
+ "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated";
+ ];
+]
+
+(* Configuration fields. *)
+let fields = [
+ ConfigString "server";
+ ConfigInt ("port", 22);
+ ConfigString "username";
+ ConfigString "password";
+ ConfigString "identity_url";
+ ConfigString "identity_file";
+ ConfigBool "identity_file_needs_update";
+ ConfigBool "sudo";
+ ConfigString "guestname";
+ ConfigInt ("vcpus", 0);
+ ConfigUInt64 "memory";
+ ConfigSection ("cpu", [
+ ConfigString "vendor";
+ ConfigString "model";
+ ConfigUnsigned "sockets";
+ ConfigUnsigned "cores";
+ ConfigUnsigned "threads";
+ ConfigBool "acpi";
+ ConfigBool "apic";
+ ConfigBool "pae";
+ ]);
+ ConfigSection ("rtc", [
+ ConfigEnum "basis";
+ ConfigInt ("offset", 0);
+ ]);
+ ConfigStringList "disks";
+ ConfigStringList "removable";
+ ConfigStringList "interfaces";
+ ConfigStringList "network_map";
+ ConfigString "output";
+ ConfigEnum "output_allocation";
+ ConfigString "output_connection";
+ ConfigString "output_format";
+ ConfigString "output_storage";
+]
+
+let name_of_config_entry = function
+ | ConfigString n
+ | ConfigInt (n, _)
+ | ConfigUnsigned n
+ | ConfigUInt64 n
+ | ConfigEnum n
+ | ConfigBool n
+ | ConfigStringList n
+ | ConfigSection (n, _) -> n
+
+let rec generate_p2v_config_h () + generate_header CStyle GPLv2plus;
+
+ pr "\
+#ifndef GUESTFS_P2V_CONFIG_H
+#define GUESTFS_P2V_CONFIG_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+";
+
+ (* Generate enums. *)
+ List.iter (
+ fun (name, fields) ->
+ pr "enum %s {\n" name;
+ List.iter (
+ fun (n, comment) ->
+ pr " %-25s /* %s */\n" (n ^ ",") comment
+ ) fields;
+ pr "};\n";
+ pr "\n"
+ ) enums;
+
+ (* Generate struct config. *)
+ generate_config_struct "config" fields;
+
+ pr "\
+extern struct config *new_config (void);
+extern struct config *copy_config (struct config *);
+extern void free_config (struct config *);
+extern void print_config (struct config *, FILE *);
+
+#endif /* GUESTFS_P2V_CONFIG_H */
+"
+
+and generate_config_struct name fields + (* If there are any ConfigSection
(sub-structs) in any of the
+ * fields then output those first.
+ *)
+ List.iter (
+ function
+ | ConfigSection (name, fields) ->
+ generate_config_struct (name ^ "_config") fields
+ | _ -> ()
+ ) fields;
+
+ (* Now generate this struct. *)
+ pr "struct %s {\n" name;
+ List.iter (
+ function
+ | ConfigString n -> pr " char *%s;\n" n
+ | ConfigInt (n, _) -> pr " int %s;\n" n
+ | ConfigUnsigned n -> pr " unsigned %s;\n" n
+ | ConfigUInt64 n -> pr " uint64_t %s;\n" n
+ | ConfigEnum n -> pr " enum %s %s;\n" n n
+ | ConfigBool n -> pr " bool %s;\n" n
+ | ConfigStringList n -> pr " char **%s;\n" n
+ | ConfigSection (n, _) -> pr " struct %s_config %s;\n" n n
+ ) fields;
+ pr "};\n";
+ pr "\n"
+
+let rec generate_p2v_config_c () + generate_header CStyle GPLv2plus;
+
+ pr "\
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <error.h>
+
+#include \"p2v.h\"
+#include \"p2v-config.h\"
+
+/**
+ * Allocate a new config struct.
+ */
+struct config *
+new_config (void)
+{
+ struct config *c;
+
+ c = calloc (1, sizeof *c);
+ if (c == NULL)
+ error (EXIT_FAILURE, errno, \"calloc\");
+
+";
+
+ generate_field_initialization "c->" fields;
+
+ pr "\
+
+ return c;
+}
+
+/**
+ * Copy a config struct.
+ */
+struct config *
+copy_config (struct config *old)
+{
+ struct config *c = new_config ();
+
+ memcpy (c, old, sizeof *c);
+
+ /* Need to deep copy strings and string lists. */
+";
+
+ generate_field_copy "c->" fields;
+
+ pr "\
+
+ return c;
+}
+
+/**
+ * Free a config struct.
+ */
+void
+free_config (struct config *c)
+{
+ if (c == NULL)
+ return;
+
+";
+
+ generate_field_free "c->" fields;
+
+pr "\
+}
+
+";
+
+ List.iter (
+ fun (name, fields) ->
+ pr "static void\n";
+ pr "print_%s (enum %s v, FILE *fp)\n" name name;
+ pr "{\n";
+ pr " switch (v) {\n";
+ List.iter (
+ fun (n, comment) ->
+ pr " case %s:\n" n;
+ pr " fprintf (fp, \"%s\");\n" comment;
+ pr " break;\n";
+ ) fields;
+ pr " }\n";
+ pr "}\n";
+ pr "\n";
+ ) enums;
+
+ pr "\
+/**
+ * Print the conversion parameters and other important information.
+ */
+void
+print_config (struct config *c, FILE *fp)
+{
+ size_t i;
+
+ fprintf (fp, \"%%-20s %%s\\n\", \"local version\",
PACKAGE_VERSION_FULL);
+ fprintf (fp, \"%%-20s %%s\\n\", \"remote version\",
+ v2v_version ? v2v_version : \"unknown\");
+";
+
+ generate_field_print None "c->" fields;
+
+pr "\
+}
+"
+
+and generate_field_initialization v fields + List.iter (
+ function
+ | ConfigInt (_, 0) -> ()
+ | ConfigInt (n, i) ->
+ pr " %s%s = %d;\n" v n i
+
+ | ConfigString _
+ | ConfigUnsigned _
+ | ConfigUInt64 _
+ | ConfigEnum _
+ | ConfigBool _
+ | ConfigStringList _ -> ()
+
+ | ConfigSection (n, fields) ->
+ let v = sprintf "%s%s." v n in
+ generate_field_initialization v fields
+ ) fields
+
+and generate_field_copy v fields + List.iter (
+ function
+ | ConfigString n ->
+ pr " if (%s%s) {\n" v n;
+ pr " %s%s = strdup (%s%s);\n" v n v n;
+ pr " if (%s%s == NULL)\n" v n;
+ pr " error (EXIT_FAILURE, errno, \"strdup: %%s\",
\"%s\");\n" n;
+ pr " }\n";
+ | ConfigStringList n ->
+ pr " if (%s%s) {\n" v n;
+ pr " %s%s = guestfs_int_copy_string_list (%s%s);\n" v n v
n;
+ pr " if (%s%s == NULL)\n" v n;
+ pr " error (EXIT_FAILURE, errno, \"copy string list:
%%s\", \"%s\");\n" n;
+ pr " }\n";
+
+ | ConfigInt _
+ | ConfigUnsigned _
+ | ConfigUInt64 _
+ | ConfigEnum _
+ | ConfigBool _ -> ()
+
+ | ConfigSection (n, fields) ->
+ let v = sprintf "%s%s." v n in
+ generate_field_copy v fields
+ ) fields
+
+and generate_field_free v fields + List.iter (
+ function
+ | ConfigString n ->
+ pr " free (%s%s);\n" v n
+ | ConfigStringList n ->
+ pr " guestfs_int_free_string_list (%s%s);\n" v n
+
+ | ConfigInt _
+ | ConfigUnsigned _
+ | ConfigUInt64 _
+ | ConfigEnum _
+ | ConfigBool _ -> ()
+
+ | ConfigSection (n, fields) ->
+ let v = sprintf "%s%s." v n in
+ generate_field_free v fields
+ ) fields
+
+and generate_field_print prefix v fields + List.iter (
+ fun field ->
+ let printable_name + match prefix with
+ | None -> name_of_config_entry field
+ | Some prefix -> prefix ^ "." ^ name_of_config_entry field
in
+
+ match field with
+ | ConfigString n ->
+ pr " fprintf (fp, \"%%-20s %%s\\n\",\n";
+ pr " \"%s\", %s%s ? %s%s :
\"(none)\");\n"
+ printable_name v n v n
+ | ConfigInt (n, _) ->
+ pr " fprintf (fp, \"%%-20s %%d\\n\",\n";
+ pr " \"%s\", %s%s);\n" printable_name v
n
+ | ConfigUnsigned n ->
+ pr " fprintf (fp, \"%%-20s %%u\\n\",\n";
+ pr " \"%s\", %s%s);\n" printable_name v
n
+ | ConfigUInt64 n ->
+ pr " fprintf (fp, \"%%-20s %%\" PRIu64
\"\\n\",\n";
+ pr " \"%s\", %s%s);\n" printable_name v
n
+ | ConfigEnum n ->
+ pr " fprintf (fp, \"%%-20s \",
\"%s\");\n" printable_name;
+ pr " print_%s (%s%s, fp);\n" n v n;
+ pr " fprintf (fp, \"\\n\");\n"
+ | ConfigBool n ->
+ pr " fprintf (fp, \"%%-20s %%s\\n\",\n";
+ pr " \"%s\", %s%s ? \"true\" :
\"false\");\n"
+ printable_name v n
+ | ConfigStringList n ->
+ pr " fprintf (fp, \"%%-20s\",
\"%s\");\n" printable_name;
+ pr " if (%s%s) {\n" v n;
+ pr " for (i = 0; %s%s[i] != NULL; ++i)\n" v n;
+ pr " fprintf (fp, \" %%s\", %s%s[i]);\n" v n;
+ pr " }\n";
+ pr " else\n";
+ pr " fprintf (fp, \" (none)\\n\");\n";
+ pr " fprintf (fp, \"\\n\");\n"
+
+ | ConfigSection (n, fields) ->
+ let v = sprintf "%s%s." v n in
+ generate_field_print (Some printable_name) v fields
+ ) fields
diff --git a/generator/p2v_config.mli b/generator/p2v_config.mli
new file mode 100644
index 000000000..55d0363a3
--- /dev/null
+++ b/generator/p2v_config.mli
@@ -0,0 +1,20 @@
+(* libguestfs
+ * Copyright (C) 2009-2018 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
+ *)
+
+val generate_p2v_config_h : unit -> unit
+val generate_p2v_config_c : unit -> unit
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
index 12b944a2f..f66c2a09b 100644
--- a/p2v/Makefile.am
+++ b/p2v/Makefile.am
@@ -18,7 +18,9 @@
include $(top_srcdir)/subdir-rules.mk
generator_built = \
- about-authors.c
+ about-authors.c \
+ config.c \
+ p2v-config.h
BUILT_SOURCES = \
$(generator_built)
@@ -90,6 +92,7 @@ virt_p2v_SOURCES = \
main.c \
nbd.c \
p2v.h \
+ p2v-config.h \
physical-xml.c \
rtc.c \
ssh.c \
diff --git a/p2v/config.c b/p2v/config.c
deleted file mode 100644
index 49e0343d1..000000000
--- a/p2v/config.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* virt-p2v
- * Copyright (C) 2009-2018 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.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <errno.h>
-#include <error.h>
-#include <locale.h>
-#include <libintl.h>
-
-#include "p2v.h"
-
-struct config *
-new_config (void)
-{
- struct config *c;
-
- c = calloc (1, sizeof *c);
- if (c == NULL)
- error (EXIT_FAILURE, errno, "calloc");
-
- c->port = 22;
-
- c->output_allocation = OUTPUT_ALLOCATION_NONE;
-
- return c;
-}
-
-struct config *
-copy_config (struct config *old)
-{
- struct config *c = new_config ();
-
- memcpy (c, old, sizeof *c);
-
- /* Need to deep copy strings and string lists. */
- if (c->server)
- c->server = strdup (c->server);
- if (c->username)
- c->username = strdup (c->username);
- if (c->password)
- c->password = strdup (c->password);
- if (c->identity_url)
- c->identity_url = strdup (c->identity_url);
- if (c->identity_file)
- c->identity_file = strdup (c->identity_file);
- if (c->guestname)
- c->guestname = strdup (c->guestname);
- if (c->cpu.vendor)
- c->cpu.vendor = strdup (c->cpu.vendor);
- if (c->cpu.model)
- c->cpu.model = strdup (c->cpu.model);
- if (c->disks)
- c->disks = guestfs_int_copy_string_list (c->disks);
- if (c->removable)
- c->removable = guestfs_int_copy_string_list (c->removable);
- if (c->interfaces)
- c->interfaces = guestfs_int_copy_string_list (c->interfaces);
- if (c->network_map)
- c->network_map = guestfs_int_copy_string_list (c->network_map);
- if (c->output)
- c->output = strdup (c->output);
- if (c->output_connection)
- c->output_connection = strdup (c->output_connection);
- if (c->output_format)
- c->output_format = strdup (c->output_format);
- if (c->output_storage)
- c->output_storage = strdup (c->output_storage);
-
- return c;
-}
-
-void
-free_config (struct config *c)
-{
- free (c->server);
- free (c->username);
- free (c->password);
- free (c->identity_url);
- free (c->identity_file);
- free (c->guestname);
- free (c->cpu.vendor);
- free (c->cpu.model);
- guestfs_int_free_string_list (c->disks);
- guestfs_int_free_string_list (c->removable);
- guestfs_int_free_string_list (c->interfaces);
- guestfs_int_free_string_list (c->network_map);
- free (c->output);
- free (c->output_connection);
- free (c->output_format);
- free (c->output_storage);
- free (c);
-}
-
-/**
- * Print the conversion parameters and other important information.
- */
-void
-print_config (struct config *config, FILE *fp)
-{
- size_t i;
-
- fprintf (fp, "local version . %s\n", PACKAGE_VERSION_FULL);
- fprintf (fp, "remote version . %s\n",
- v2v_version ? v2v_version : "unknown");
- fprintf (fp, "conversion server %s\n",
- config->server ? config->server : "none");
- fprintf (fp, "port . . . . . . %d\n", config->port);
- fprintf (fp, "username . . . . %s\n",
- config->username ? config->username : "none");
- fprintf (fp, "password . . . . %s\n",
- config->password && strlen (config->password) > 0 ?
"***" : "none");
- fprintf (fp, "identity URL . . %s\n",
- config->identity_url ? config->identity_url :
"none");
- fprintf (fp, "sudo . . . . . . %s\n",
- config->sudo ? "true" : "false");
- fprintf (fp, "guest name . . . %s\n",
- config->guestname ? config->guestname : "none");
- fprintf (fp, "vcpus . . . . . %d\n", config->vcpus);
- fprintf (fp, "memory . . . . . %" PRIu64 "\n",
config->memory);
- if (config->cpu.vendor)
- fprintf (fp, "cpu vendor . . . %s\n", config->cpu.vendor);
- if (config->cpu.model)
- fprintf (fp, "cpu model . . . %s\n", config->cpu.model);
- if (config->cpu.sockets > 0)
- fprintf (fp, "cpu sockets . . %u\n", config->cpu.sockets);
- if (config->cpu.cores > 0)
- fprintf (fp, "cpu cores . . . %u\n", config->cpu.cores);
- if (config->cpu.threads > 0)
- fprintf (fp, "cpu threads . . %u\n", config->cpu.threads);
- fprintf (fp, "flags . . . . . %s%s%s\n",
- config->cpu.acpi ? " acpi" : "",
- config->cpu.apic ? " apic" : "",
- config->cpu.pae ? " pae" : "");
- fprintf (fp, "rtc offset . . . ");
- switch (config->rtc.basis) {
- case BASIS_UNKNOWN:
- fprintf (fp, "unknown");
- break;
- case BASIS_UTC:
- fprintf (fp, "%d seconds from UTC", config->rtc.offset);
- break;
- case BASIS_LOCALTIME:
- fprintf (fp, "%d seconds from localtime", config->rtc.offset);
- break;
- }
- fprintf (fp, "\n");
- fprintf (fp, "disks . . . . . ");
- if (config->disks != NULL) {
- for (i = 0; config->disks[i] != NULL; ++i)
- fprintf (fp, " %s", config->disks[i]);
- }
- fprintf (fp, "\n");
- fprintf (fp, "removable . . . ");
- if (config->removable != NULL) {
- for (i = 0; config->removable[i] != NULL; ++i)
- fprintf (fp, " %s", config->removable[i]);
- }
- fprintf (fp, "\n");
- fprintf (fp, "interfaces . . . ");
- if (config->interfaces != NULL) {
- for (i = 0; config->interfaces[i] != NULL; ++i)
- fprintf (fp, " %s", config->interfaces[i]);
- }
- fprintf (fp, "\n");
- fprintf (fp, "network map . . ");
- if (config->network_map != NULL) {
- for (i = 0; config->network_map[i] != NULL; ++i)
- fprintf (fp, " %s", config->network_map[i]);
- }
- fprintf (fp, "\n");
- fprintf (fp, "output . . . . . %s\n",
- config->output ? config->output : "none");
- fprintf (fp, "output alloc . . ");
- switch (config->output_allocation) {
- case OUTPUT_ALLOCATION_NONE: fprintf (fp, "none"); break;
- case OUTPUT_ALLOCATION_SPARSE: fprintf (fp, "sparse"); break;
- case OUTPUT_ALLOCATION_PREALLOCATED: fprintf (fp, "preallocated");
break;
- default: fprintf (fp, "unknown? (%d)",
config->output_allocation);
- }
- fprintf (fp, "\n");
- fprintf (fp, "output conn . . %s\n",
- config->output_connection ? config->output_connection :
"none");
- fprintf (fp, "output format . %s\n",
- config->output_format ? config->output_format :
"none");
- fprintf (fp, "output storage . %s\n",
- config->output_storage ? config->output_storage :
"none");
-}
diff --git a/p2v/p2v.h b/p2v/p2v.h
index b72a4832d..021ea2946 100644
--- a/p2v/p2v.h
+++ b/p2v/p2v.h
@@ -28,6 +28,7 @@
#define DEBUG_STDERR 1
#include "miniexpect.h"
+#include "p2v-config.h"
/* We don't use libguestfs directly here, and we don't link to it
* either (in fact, we don't want libguestfs on the ISO). However
@@ -59,61 +60,6 @@ extern int feature_colours_option;
/* virt-p2v --colours option (used by ansi_* macros). */
extern int force_colour;
-/* config.c */
-struct cpu_config {
- char *vendor; /* eg. "Intel" */
- char *model; /* eg. "Broadwell" */
- unsigned sockets; /* number of sockets */
- unsigned cores; /* number of cores per socket */
- unsigned threads; /* number of hyperthreads per core */
- bool acpi;
- bool apic;
- bool pae;
-};
-
-struct rtc_config {
- enum {
- BASIS_UNKNOWN, /* RTC could not be read. */
- BASIS_UTC, /* RTC is either UTC or an offset from UTC. */
- BASIS_LOCALTIME, /* RTC is localtime. */
- } basis;
- int offset; /* RTC seconds offset from basis. */
-};
-
-struct config {
- char *server;
- int port;
- char *username;
- char *password;
- char *identity_url;
- char *identity_file; /* Used to cache the downloaded identity_url. */
- int identity_file_needs_update;
- int sudo;
- char *guestname;
- int vcpus;
- uint64_t memory;
- struct cpu_config cpu;
- struct rtc_config rtc;
- char **disks;
- char **removable;
- char **interfaces;
- char **network_map;
- char *output;
- int output_allocation;
- char *output_connection;
- char *output_format;
- char *output_storage;
-};
-
-#define OUTPUT_ALLOCATION_NONE 0
-#define OUTPUT_ALLOCATION_SPARSE 1
-#define OUTPUT_ALLOCATION_PREALLOCATED 2
-
-extern struct config *new_config (void);
-extern struct config *copy_config (struct config *);
-extern void free_config (struct config *);
-extern void print_config (struct config *, FILE *);
-
/* cpuid.c */
extern void get_cpu_config (struct cpu_config *);
diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh
index 770b7a825..f0077f750 100755
--- a/p2v/test-virt-p2v-cmdline.sh
+++ b/p2v/test-virt-p2v-cmdline.sh
@@ -33,21 +33,21 @@ $VG virt-p2v --cmdline='p2v.server=localhost
p2v.port=123 p2v.username=user p2v.
cat $out
# Check the output contains what we expect.
-grep "^conversion server.*localhost" $out
+grep "^server.*localhost" $out
grep "^port.*123" $out
grep "^username.*user" $out
grep "^sudo.*false" $out
-grep "^guest name.*test" $out
+grep "^guestname.*test" $out
grep "^vcpus.*4" $out
grep "^memory.*"$((1024*1024*1024)) $out
grep "^disks.*sda sdb sdc" $out
grep "^removable.*sdd" $out
grep "^interfaces.*eth0 eth1" $out
-grep "^network map.*em1:wired other" $out
+grep "^network_map.*em1:wired other" $out
grep "^output.*local" $out
-grep "^output alloc.*sparse" $out
-grep "^output conn.*qemu:///session" $out
-grep "^output format.*raw" $out
-grep "^output storage.*/var/tmp" $out
+grep "^output_allocation.*sparse" $out
+grep "^output_connection.*qemu:///session" $out
+grep "^output_format.*raw" $out
+grep "^output_storage.*/var/tmp" $out
rm $out
--
2.17.1
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 2/3] p2v: Group configuration settings in sections.
Since the previous commit introduced configuration sections, we can
now group more configuration settings together in these sections.
This is just a renaming of certain fields.
---
generator/p2v_config.ml | 46 ++++++++++-------
p2v/conversion.c | 18 +++----
p2v/gui.c | 96 ++++++++++++++++++------------------
p2v/kernel.c | 44 ++++++++---------
p2v/main.c | 6 +--
p2v/ssh.c | 56 ++++++++++-----------
p2v/test-virt-p2v-cmdline.sh | 18 +++----
7 files changed, 146 insertions(+), 138 deletions(-)
diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml
index 1f998fd7c..e0347d6c2 100644
--- a/generator/p2v_config.ml
+++ b/generator/p2v_config.ml
@@ -34,7 +34,7 @@ type config_entry | ConfigInt of string * int (* field
name, initial value *)
| ConfigUnsigned of string
| ConfigUInt64 of string
- | ConfigEnum of string
+ | ConfigEnum of string * string (* field name, enum *)
| ConfigBool of string
| ConfigStringList of string
| ConfigSection of string * config_entry list
@@ -55,14 +55,20 @@ let enums = [
(* Configuration fields. *)
let fields = [
- ConfigString "server";
- ConfigInt ("port", 22);
- ConfigString "username";
- ConfigString "password";
- ConfigString "identity_url";
- ConfigString "identity_file";
- ConfigBool "identity_file_needs_update";
- ConfigBool "sudo";
+ ConfigSection ("remote", [
+ ConfigString "server";
+ ConfigInt ("port", 22);
+ ]);
+ ConfigSection ("auth", [
+ ConfigString "username";
+ ConfigString "password";
+ ConfigSection ("identity", [
+ ConfigString "url";
+ ConfigString "file";
+ ConfigBool
"file_needs_update";
+ ]);
+ ConfigBool "sudo";
+ ]);
ConfigString "guestname";
ConfigInt ("vcpus", 0);
ConfigUInt64 "memory";
@@ -77,18 +83,20 @@ let fields = [
ConfigBool "pae";
]);
ConfigSection ("rtc", [
- ConfigEnum "basis";
+ ConfigEnum ("basis", "basis");
ConfigInt ("offset", 0);
]);
ConfigStringList "disks";
ConfigStringList "removable";
ConfigStringList "interfaces";
ConfigStringList "network_map";
- ConfigString "output";
- ConfigEnum "output_allocation";
- ConfigString "output_connection";
- ConfigString "output_format";
- ConfigString "output_storage";
+ ConfigSection ("output", [
+ ConfigString "type";
+ ConfigEnum ("allocation",
"output_allocation");
+ ConfigString "connection";
+ ConfigString "format";
+ ConfigString "storage";
+ ]);
]
let name_of_config_entry = function
@@ -96,7 +104,7 @@ let name_of_config_entry = function
| ConfigInt (n, _)
| ConfigUnsigned n
| ConfigUInt64 n
- | ConfigEnum n
+ | ConfigEnum (n, _)
| ConfigBool n
| ConfigStringList n
| ConfigSection (n, _) -> n
@@ -156,7 +164,7 @@ and generate_config_struct name fields | ConfigInt (n,
_) -> pr " int %s;\n" n
| ConfigUnsigned n -> pr " unsigned %s;\n" n
| ConfigUInt64 n -> pr " uint64_t %s;\n" n
- | ConfigEnum n -> pr " enum %s %s;\n" n n
+ | ConfigEnum (n, enum) -> pr " enum %s %s;\n" enum n
| ConfigBool n -> pr " bool %s;\n" n
| ConfigStringList n -> pr " char **%s;\n" n
| ConfigSection (n, _) -> pr " struct %s_config %s;\n" n n
@@ -365,9 +373,9 @@ and generate_field_print prefix v fields |
ConfigUInt64 n ->
pr " fprintf (fp, \"%%-20s %%\" PRIu64
\"\\n\",\n";
pr " \"%s\", %s%s);\n" printable_name v
n
- | ConfigEnum n ->
+ | ConfigEnum (n, enum) ->
pr " fprintf (fp, \"%%-20s \",
\"%s\");\n" printable_name;
- pr " print_%s (%s%s, fp);\n" n v n;
+ pr " print_%s (%s%s, fp);\n" enum v n;
pr " fprintf (fp, \"\\n\");\n"
| ConfigBool n ->
pr " fprintf (fp, \"%%-20s %%s\\n\",\n";
diff --git a/p2v/conversion.c b/p2v/conversion.c
index b9da033db..dd056c69a 100644
--- a/p2v/conversion.c
+++ b/p2v/conversion.c
@@ -498,19 +498,19 @@ generate_wrapper_script (struct config *config, const char
*remote_dir,
/* The virt-v2v command, as a shell function called "v2v". */
fprintf (fp, "v2v ()\n");
fprintf (fp, "{\n");
- if (config->sudo)
+ if (config->auth.sudo)
fprintf (fp, "sudo -n ");
fprintf (fp, "virt-v2v -v -x");
if (feature_colours_option)
fprintf (fp, " --colours");
fprintf (fp, " -i libvirtxml");
- if (config->output) { /* -o */
+ if (config->output.type) { /* -o */
fprintf (fp, " -o ");
- print_quoted (fp, config->output);
+ print_quoted (fp, config->output.type);
}
- switch (config->output_allocation) { /* -oa */
+ switch (config->output.allocation) { /* -oa */
case OUTPUT_ALLOCATION_NONE:
/* nothing */
break;
@@ -524,14 +524,14 @@ generate_wrapper_script (struct config *config, const char
*remote_dir,
abort ();
}
- if (config->output_format) { /* -of */
+ if (config->output.format) { /* -of */
fprintf (fp, " -of ");
- print_quoted (fp, config->output_format);
+ print_quoted (fp, config->output.format);
}
- if (config->output_storage) { /* -os */
+ if (config->output.storage) { /* -os */
fprintf (fp, " -os ");
- print_quoted (fp, config->output_storage);
+ print_quoted (fp, config->output.storage);
}
fprintf (fp, " --root first");
@@ -562,7 +562,7 @@ generate_wrapper_script (struct config *config, const char
*remote_dir,
fprintf (fp,
"# Log the version of virt-v2v (for information
only).\n");
- if (config->sudo)
+ if (config->auth.sudo)
fprintf (fp, "sudo -n ");
fprintf (fp, "virt-v2v --version > v2v-version\n");
fprintf (fp, "\n");
diff --git a/p2v/gui.c b/p2v/gui.c
index f596890c2..7ec2900a8 100644
--- a/p2v/gui.c
+++ b/p2v/gui.c
@@ -228,12 +228,12 @@ create_connection_dialog (struct config *config)
hbox_new (server_hbox, FALSE, 4);
server_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (server_label), server_entry);
- if (config->server != NULL)
- gtk_entry_set_text (GTK_ENTRY (server_entry), config->server);
+ if (config->remote.server != NULL)
+ gtk_entry_set_text (GTK_ENTRY (server_entry), config->remote.server);
port_colon_label = gtk_label_new (":");
port_entry = gtk_entry_new ();
gtk_entry_set_width_chars (GTK_ENTRY (port_entry), 6);
- snprintf (port_str, sizeof port_str, "%d", config->port);
+ snprintf (port_str, sizeof port_str, "%d", config->remote.port);
gtk_entry_set_text (GTK_ENTRY (port_entry), port_str);
gtk_box_pack_start (GTK_BOX (server_hbox), server_entry, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (server_hbox), port_colon_label, FALSE, FALSE,
0);
@@ -247,8 +247,8 @@ create_connection_dialog (struct config *config)
set_alignment (username_label, 1., 0.5);
username_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (username_label), username_entry);
- if (config->username != NULL)
- gtk_entry_set_text (GTK_ENTRY (username_entry), config->username);
+ if (config->auth.username != NULL)
+ gtk_entry_set_text (GTK_ENTRY (username_entry), config->auth.username);
else
gtk_entry_set_text (GTK_ENTRY (username_entry), "root");
table_attach (table, username_entry,
@@ -265,8 +265,8 @@ create_connection_dialog (struct config *config)
gtk_entry_set_input_purpose (GTK_ENTRY (password_entry),
GTK_INPUT_PURPOSE_PASSWORD);
#endif
- if (config->password != NULL)
- gtk_entry_set_text (GTK_ENTRY (password_entry), config->password);
+ if (config->auth.password != NULL)
+ gtk_entry_set_text (GTK_ENTRY (password_entry), config->auth.password);
table_attach (table, password_entry,
1, 2, 2, 3, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4);
@@ -276,15 +276,15 @@ create_connection_dialog (struct config *config)
set_alignment (identity_label, 1., 0.5);
identity_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (identity_label), identity_entry);
- if (config->identity_url != NULL)
- gtk_entry_set_text (GTK_ENTRY (identity_entry), config->identity_url);
+ if (config->auth.identity.url != NULL)
+ gtk_entry_set_text (GTK_ENTRY (identity_entry),
config->auth.identity.url);
table_attach (table, identity_entry,
1, 2, 3, 4, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4);
sudo_button gtk_check_button_new_with_mnemonic (_("Use su_do when
running virt-v2v"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sudo_button),
- config->sudo);
+ config->auth.sudo);
table_attach (table, sudo_button,
1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4);
@@ -446,42 +446,42 @@ test_connection_clicked (GtkWidget *w, gpointer data)
#endif
/* Get the fields from the various widgets. */
- free (config->server);
- config->server = strdup (gtk_entry_get_text (GTK_ENTRY (server_entry)));
- if (STREQ (config->server, "")) {
+ free (config->remote.server);
+ config->remote.server = strdup (gtk_entry_get_text (GTK_ENTRY
(server_entry)));
+ if (STREQ (config->remote.server, "")) {
gtk_label_set_text (GTK_LABEL (spinner_message),
_("error: No conversion server given."));
gtk_widget_grab_focus (server_entry);
errors++;
}
port_str = gtk_entry_get_text (GTK_ENTRY (port_entry));
- if (sscanf (port_str, "%d", &config->port) != 1 ||
- config->port <= 0 || config->port >= 65536) {
+ if (sscanf (port_str, "%d", &config->remote.port) != 1 ||
+ config->remote.port <= 0 || config->remote.port >= 65536) {
gtk_label_set_text (GTK_LABEL (spinner_message),
_("error: Invalid port number. If in doubt, use
\"22\"."));
gtk_widget_grab_focus (port_entry);
errors++;
}
- free (config->username);
- config->username = strdup (gtk_entry_get_text (GTK_ENTRY
(username_entry)));
- if (STREQ (config->username, "")) {
+ free (config->auth.username);
+ config->auth.username = strdup (gtk_entry_get_text (GTK_ENTRY
(username_entry)));
+ if (STREQ (config->auth.username, "")) {
gtk_label_set_text (GTK_LABEL (spinner_message),
_("error: No user name. If in doubt, use
\"root\"."));
gtk_widget_grab_focus (username_entry);
errors++;
}
- free (config->password);
- config->password = strdup (gtk_entry_get_text (GTK_ENTRY
(password_entry)));
+ free (config->auth.password);
+ config->auth.password = strdup (gtk_entry_get_text (GTK_ENTRY
(password_entry)));
- free (config->identity_url);
+ free (config->auth.identity.url);
identity_str = gtk_entry_get_text (GTK_ENTRY (identity_entry));
if (identity_str && STRNEQ (identity_str, ""))
- config->identity_url = strdup (identity_str);
+ config->auth.identity.url = strdup (identity_str);
else
- config->identity_url = NULL;
- config->identity_file_needs_update = 1;
+ config->auth.identity.url = NULL;
+ config->auth.identity.file_needs_update = 1;
- config->sudo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
(sudo_button));
+ config->auth.sudo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
(sudo_button));
if (errors)
return;
@@ -839,8 +839,8 @@ create_conversion_dialog (struct config *config)
oc_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (oc_label), oc_entry);
gtk_widget_set_tooltip_markup (oc_entry, _("For
<b>libvirt</b> only, the libvirt connection URI, or leave blank to
add the guest to the default libvirt instance on the conversion server. For
others, leave this field blank."));
- if (config->output_connection != NULL)
- gtk_entry_set_text (GTK_ENTRY (oc_entry), config->output_connection);
+ if (config->output.connection != NULL)
+ gtk_entry_set_text (GTK_ENTRY (oc_entry), config->output.connection);
table_attach (output_tbl, oc_entry,
1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
@@ -851,8 +851,8 @@ create_conversion_dialog (struct config *config)
os_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (os_label), os_entry);
gtk_widget_set_tooltip_markup (os_entry, _("For
<b>local</b>, put the directory name on the conversion server. For
<b>rhv</b>, put the Export Storage Domain (server:/mountpoint). For
others, leave this field blank."));
- if (config->output_storage != NULL)
- gtk_entry_set_text (GTK_ENTRY (os_entry), config->output_storage);
+ if (config->output.storage != NULL)
+ gtk_entry_set_text (GTK_ENTRY (os_entry), config->output.storage);
table_attach (output_tbl, os_entry,
1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
@@ -863,8 +863,8 @@ create_conversion_dialog (struct config *config)
of_entry = gtk_entry_new ();
gtk_label_set_mnemonic_widget (GTK_LABEL (of_label), of_entry);
gtk_widget_set_tooltip_markup (of_entry, _("The output disk format,
typically <b>raw</b> or <b>qcow2</b>. If blank,
defaults to <b>raw</b>."));
- if (config->output_format != NULL)
- gtk_entry_set_text (GTK_ENTRY (of_entry), config->output_format);
+ if (config->output.format != NULL)
+ gtk_entry_set_text (GTK_ENTRY (of_entry), config->output.format);
table_attach (output_tbl, of_entry,
1, 2, 3, 4, GTK_FILL, GTK_FILL, 1, 1);
@@ -878,7 +878,7 @@ create_conversion_dialog (struct config *config)
"sparse");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (oa_combo),
"preallocated");
- switch (config->output_allocation) {
+ switch (config->output.allocation) {
case OUTPUT_ALLOCATION_PREALLOCATED:
gtk_combo_box_set_active (GTK_COMBO_BOX (oa_combo), 1);
break;
@@ -1034,8 +1034,8 @@ repopulate_output_combo (struct config *config)
size_t i;
/* Which driver is currently selected? */
- if (config && config->output)
- output = strdup (config->output);
+ if (config && config->output.type)
+ output = strdup (config->output.type);
else
output = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (o_combo));
@@ -1981,40 +1981,40 @@ start_conversion_clicked (GtkWidget *w, gpointer data)
set_network_map_from_ui (config);
/* Output selection. */
- free (config->output);
- config->output + free (config->output.type);
+ config->output.type gtk_combo_box_text_get_active_text
(GTK_COMBO_BOX_TEXT (o_combo));
- config->output_allocation = OUTPUT_ALLOCATION_NONE;
+ config->output.allocation = OUTPUT_ALLOCATION_NONE;
str2 = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (oa_combo));
if (str2) {
if (STREQ (str2, "sparse"))
- config->output_allocation = OUTPUT_ALLOCATION_SPARSE;
+ config->output.allocation = OUTPUT_ALLOCATION_SPARSE;
else if (STREQ (str2, "preallocated"))
- config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED;
+ config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED;
free (str2);
}
- free (config->output_connection);
+ free (config->output.connection);
str = gtk_entry_get_text (GTK_ENTRY (oc_entry));
if (str && STRNEQ (str, ""))
- config->output_connection = strdup (str);
+ config->output.connection = strdup (str);
else
- config->output_connection = NULL;
+ config->output.connection = NULL;
- free (config->output_format);
+ free (config->output.format);
str = gtk_entry_get_text (GTK_ENTRY (of_entry));
if (str && STRNEQ (str, ""))
- config->output_format = strdup (str);
+ config->output.format = strdup (str);
else
- config->output_format = NULL;
+ config->output.format = NULL;
- free (config->output_storage);
+ free (config->output.storage);
str = gtk_entry_get_text (GTK_ENTRY (os_entry));
if (str && STRNEQ (str, ""))
- config->output_storage = strdup (str);
+ config->output.storage = strdup (str);
else
- config->output_storage = NULL;
+ config->output.storage = NULL;
/* Display the UI for conversion. */
show_running_dialog ();
diff --git a/p2v/kernel.c b/p2v/kernel.c
index 5da80808b..4f999755e 100644
--- a/p2v/kernel.c
+++ b/p2v/kernel.c
@@ -49,39 +49,39 @@ update_config_from_kernel_cmdline (struct config *config,
char **cmdline)
p = get_cmdline_key (cmdline, "p2v.server");
if (p) {
- free (config->server);
- config->server = strdup (p);
+ free (config->remote.server);
+ config->remote.server = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.port");
if (p) {
- if (sscanf (p, "%d", &config->port) != 1)
+ if (sscanf (p, "%d", &config->remote.port) != 1)
error (EXIT_FAILURE, 0,
"cannot parse p2v.port from kernel command line");
}
p = get_cmdline_key (cmdline, "p2v.username");
if (p) {
- free (config->username);
- config->username = strdup (p);
+ free (config->auth.username);
+ config->auth.username = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.password");
if (p) {
- free (config->password);
- config->password = strdup (p);
+ free (config->auth.password);
+ config->auth.password = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.identity");
if (p) {
- free (config->identity_url);
- config->identity_url = strdup (p);
- config->identity_file_needs_update = 1;
+ free (config->auth.identity.url);
+ config->auth.identity.url = strdup (p);
+ config->auth.identity.file_needs_update = 1;
}
p = get_cmdline_key (cmdline, "p2v.sudo");
if (p)
- config->sudo = 1;
+ config->auth.sudo = 1;
p = get_cmdline_key (cmdline, "p2v.name");
if (p) {
@@ -153,16 +153,16 @@ update_config_from_kernel_cmdline (struct config *config,
char **cmdline)
p = get_cmdline_key (cmdline, "p2v.o");
if (p) {
- free (config->output);
- config->output = strdup (p);
+ free (config->output.type);
+ config->output.type = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.oa");
if (p) {
if (STREQ (p, "sparse"))
- config->output_allocation = OUTPUT_ALLOCATION_SPARSE;
+ config->output.allocation = OUTPUT_ALLOCATION_SPARSE;
else if (STREQ (p, "preallocated"))
- config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED;
+ config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED;
else
fprintf (stderr, "%s: warning: don't know what p2v.oa=%s
means\n",
getprogname (), p);
@@ -170,20 +170,20 @@ update_config_from_kernel_cmdline (struct config *config,
char **cmdline)
p = get_cmdline_key (cmdline, "p2v.oc");
if (p) {
- free (config->output_connection);
- config->output_connection = strdup (p);
+ free (config->output.connection);
+ config->output.connection = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.of");
if (p) {
- free (config->output_format);
- config->output_format = strdup (p);
+ free (config->output.format);
+ config->output.format = strdup (p);
}
p = get_cmdline_key (cmdline, "p2v.os");
if (p) {
- free (config->output_storage);
- config->output_storage = strdup (p);
+ free (config->output.storage);
+ config->output.storage = strdup (p);
}
/* Undocumented command line parameter used for testing command line
@@ -216,7 +216,7 @@ kernel_conversion (struct config *config, char **cmdline,
int cmdline_source)
error (EXIT_FAILURE, 0,
"error opening control connection to %s:%d: %s",
- config->server, config->port, err);
+ config->remote.server, config->remote.port, err);
}
}
diff --git a/p2v/main.c b/p2v/main.c
index 3c8572bda..a5f13924e 100644
--- a/p2v/main.c
+++ b/p2v/main.c
@@ -249,7 +249,7 @@ main (int argc, char *argv[])
/* If p2v.server exists, then we use the non-interactive kernel
* conversion. Otherwise we run the GUI.
*/
- if (config->server != NULL)
+ if (config->remote.server != NULL)
kernel_conversion (config, cmdline, cmdline_source);
else {
if (!gui_possible)
@@ -372,8 +372,8 @@ set_config_defaults (struct config *config)
/* Default output drops the guest onto /var/tmp on the conversion
* server, a hopefully safe default.
*/
- config->output = strdup ("local");
- config->output_storage = strdup ("/var/tmp");
+ config->output.type = strdup ("local");
+ config->output.storage = strdup ("/var/tmp");
}
static int
diff --git a/p2v/ssh.c b/p2v/ssh.c
index 15f53b692..db43c42a3 100644
--- a/p2v/ssh.c
+++ b/p2v/ssh.c
@@ -276,7 +276,7 @@ curl_download (const char *url, const char *local_file)
}
/**
- * Re-cache the C<config-E<gt>identity_url> if needed.
+ * Re-cache the C<config-E<gt>identity.url> if needed.
*/
static int
cache_ssh_identity (struct config *config)
@@ -284,25 +284,25 @@ cache_ssh_identity (struct config *config)
int fd;
/* If it doesn't need downloading, return. */
- if (config->identity_url == NULL ||
- !config->identity_file_needs_update)
+ if (config->auth.identity.url == NULL ||
+ !config->auth.identity.file_needs_update)
return 0;
/* Generate a random filename. */
- free (config->identity_file);
- config->identity_file = strdup ("/tmp/id.XXXXXX");
- if (config->identity_file == NULL)
+ free (config->auth.identity.file);
+ config->auth.identity.file = strdup ("/tmp/id.XXXXXX");
+ if (config->auth.identity.file == NULL)
error (EXIT_FAILURE, errno, "strdup");
- fd = mkstemp (config->identity_file);
+ fd = mkstemp (config->auth.identity.file);
if (fd == -1)
error (EXIT_FAILURE, errno, "mkstemp");
close (fd);
/* Curl download URL to file. */
- if (curl_download (config->identity_url, config->identity_file) == -1)
{
- free (config->identity_file);
- config->identity_file = NULL;
- config->identity_file_needs_update = 1;
+ if (curl_download (config->auth.identity.url,
config->auth.identity.file) == -1) {
+ free (config->auth.identity.file);
+ config->auth.identity.file = NULL;
+ config->auth.identity.file_needs_update = 1;
return -1;
}
@@ -343,14 +343,14 @@ start_ssh (unsigned spawn_flags, struct config *config,
return NULL;
/* Are we using password or identity authentication? */
- using_password_auth = config->identity_file == NULL;
+ using_password_auth = config->auth.identity.file == NULL;
ADD_ARG (argv, i, "ssh");
ADD_ARG (argv, i, "-p"); /* Port. */
- snprintf (port_str, sizeof port_str, "%d", config->port);
+ snprintf (port_str, sizeof port_str, "%d", config->remote.port);
ADD_ARG (argv, i, port_str);
ADD_ARG (argv, i, "-l"); /* Username. */
- ADD_ARG (argv, i, config->username ? config->username :
"root");
+ ADD_ARG (argv, i, config->auth.username ? config->auth.username :
"root");
ADD_ARG (argv, i, "-o"); /* Host key will always be novel. */
ADD_ARG (argv, i, "StrictHostKeyChecking=no");
ADD_ARG (argv, i, "-o"); /* ConnectTimeout */
@@ -371,13 +371,13 @@ start_ssh (unsigned spawn_flags, struct config *config,
ADD_ARG (argv, i, "-o");
ADD_ARG (argv, i, "PreferredAuthentications=publickey");
ADD_ARG (argv, i, "-i");
- ADD_ARG (argv, i, config->identity_file);
+ ADD_ARG (argv, i, config->auth.identity.file);
}
if (extra_args != NULL) {
for (size_t j = 0; extra_args[j] != NULL; ++j)
ADD_ARG (argv, i, extra_args[j]);
}
- ADD_ARG (argv, i, config->server); /* Conversion server. */
+ ADD_ARG (argv, i, config->remote.server); /* Conversion server. */
ADD_ARG (argv, i, NULL);
#if DEBUG_STDERR
@@ -408,7 +408,7 @@ start_ssh (unsigned spawn_flags, struct config *config,
mexp_set_timeout (h, SSH_TIMEOUT + 20);
if (using_password_auth &&
- config->password && strlen (config->password) > 0) {
+ config->auth.password && strlen (config->auth.password)
> 0) {
CLEANUP_FREE char *ssh_message = NULL;
/* Wait for the password prompt. */
@@ -420,7 +420,7 @@ start_ssh (unsigned spawn_flags, struct config *config,
{ 0 }
}, ovector, ovecsize)) {
case 100: /* Got password prompt. */
- if (mexp_printf_password (h, "%s", config->password) == -1
||
+ if (mexp_printf_password (h, "%s", config->auth.password) ==
-1 ||
mexp_printf (h, "\n") == -1) {
set_ssh_mexp_error ("mexp_printf");
mexp_close (h);
@@ -605,11 +605,11 @@ scp_file (struct config *config, const char *target, const
char *local, ...)
return -1;
/* Are we using password or identity authentication? */
- using_password_auth = config->identity_file == NULL;
+ using_password_auth = config->auth.identity.file == NULL;
ADD_ARG (argv, i, "scp");
ADD_ARG (argv, i, "-P"); /* Port. */
- snprintf (port_str, sizeof port_str, "%d", config->port);
+ snprintf (port_str, sizeof port_str, "%d", config->remote.port);
ADD_ARG (argv, i, port_str);
ADD_ARG (argv, i, "-o"); /* Host key will always be novel. */
ADD_ARG (argv, i, "StrictHostKeyChecking=no");
@@ -627,7 +627,7 @@ scp_file (struct config *config, const char *target, const
char *local, ...)
ADD_ARG (argv, i, "-o");
ADD_ARG (argv, i, "PreferredAuthentications=publickey");
ADD_ARG (argv, i, "-i");
- ADD_ARG (argv, i, config->identity_file);
+ ADD_ARG (argv, i, config->auth.identity.file);
}
/* Source files or directories.
@@ -643,8 +643,8 @@ scp_file (struct config *config, const char *target, const
char *local, ...)
* "username@server:target".
*/
if (asprintf (&remote, "%s@%s:%s",
- config->username ? config->username : "root",
- config->server, target) == -1)
+ config->auth.username ? config->auth.username :
"root",
+ config->remote.server, target) == -1)
error (EXIT_FAILURE, errno, "asprintf");
ADD_ARG (argv, i, remote);
@@ -678,7 +678,7 @@ scp_file (struct config *config, const char *target, const
char *local, ...)
mexp_set_timeout (h, SSH_TIMEOUT + 20);
if (using_password_auth &&
- config->password && strlen (config->password) > 0) {
+ config->auth.password && strlen (config->auth.password)
> 0) {
CLEANUP_FREE char *ssh_message = NULL;
/* Wait for the password prompt. */
@@ -690,7 +690,7 @@ scp_file (struct config *config, const char *target, const
char *local, ...)
{ 0 }
}, ovector, ovecsize)) {
case 100: /* Got password prompt. */
- if (mexp_printf_password (h, "%s", config->password) == -1
||
+ if (mexp_printf_password (h, "%s", config->auth.password) ==
-1 ||
mexp_printf (h, "\n") == -1) {
set_ssh_mexp_error ("mexp_printf");
mexp_close (h);
@@ -793,7 +793,7 @@ test_connection (struct config *config)
*/
if (mexp_printf (h,
"%svirt-v2v --version\n",
- config->sudo ? "sudo -n " : "") ==
-1) {
+ config->auth.sudo ? "sudo -n " : "")
== -1) {
set_ssh_mexp_error ("mexp_printf");
mexp_close (h);
return -1;
@@ -818,7 +818,7 @@ test_connection (struct config *config)
case 101:
set_ssh_error ("sudo for user \"%s\" requires a password.
Edit /etc/sudoers on the conversion server to ensure the \"NOPASSWD:\"
option is set for this user.",
- config->username);
+ config->auth.username);
mexp_close (h);
return -1;
@@ -871,7 +871,7 @@ test_connection (struct config *config)
/* Get virt-v2v features. See: v2v/cmdline.ml */
if (mexp_printf (h, "%svirt-v2v --machine-readable\n",
- config->sudo ? "sudo -n " : "") ==
-1) {
+ config->auth.sudo ? "sudo -n " : "")
== -1) {
set_ssh_mexp_error ("mexp_printf");
mexp_close (h);
return -1;
diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh
index f0077f750..2fbca1eb5 100755
--- a/p2v/test-virt-p2v-cmdline.sh
+++ b/p2v/test-virt-p2v-cmdline.sh
@@ -33,10 +33,10 @@ $VG virt-p2v --cmdline='p2v.server=localhost
p2v.port=123 p2v.username=user p2v.
cat $out
# Check the output contains what we expect.
-grep "^server.*localhost" $out
-grep "^port.*123" $out
-grep "^username.*user" $out
-grep "^sudo.*false" $out
+grep "^remote\.server.*localhost" $out
+grep "^remote\.port.*123" $out
+grep "^auth\.username.*user" $out
+grep "^auth\.sudo.*false" $out
grep "^guestname.*test" $out
grep "^vcpus.*4" $out
grep "^memory.*"$((1024*1024*1024)) $out
@@ -44,10 +44,10 @@ grep "^disks.*sda sdb sdc" $out
grep "^removable.*sdd" $out
grep "^interfaces.*eth0 eth1" $out
grep "^network_map.*em1:wired other" $out
-grep "^output.*local" $out
-grep "^output_allocation.*sparse" $out
-grep "^output_connection.*qemu:///session" $out
-grep "^output_format.*raw" $out
-grep "^output_storage.*/var/tmp" $out
+grep "^output\.type.*local" $out
+grep "^output\.allocation.*sparse" $out
+grep "^output\.connection.*qemu:///session" $out
+grep "^output\.format.*raw" $out
+grep "^output\.storage.*/var/tmp" $out
rm $out
--
2.17.1
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 3/3] p2v: Generate the code and docs for parsing the kernel command line.
As a side effect, a lot more fields are now settable on the
kernel command line.
Existing kernel command lines & corresponding documentation should
still remain backwards compatible.
---
.gitignore | 2 +
generator/main.ml | 4 +
generator/p2v_config.ml | 458 ++++++++++++++++++++++++++++++++++++++-
generator/p2v_config.mli | 2 +
p2v/Makefile.am | 8 +-
p2v/kernel.c | 154 -------------
p2v/p2v.h | 4 +-
p2v/virt-p2v.pod | 131 +----------
po-docs/language.mk | 8 +
po-docs/podfiles | 1 +
10 files changed, 475 insertions(+), 297 deletions(-)
diff --git a/.gitignore b/.gitignore
index 4c0ff4e1e..d855459f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -435,6 +435,7 @@ Makefile.in
/p2v/dependencies.debian
/p2v/dependencies.redhat
/p2v/dependencies.suse
+/p2v/kernel-config.c
/p2v/p2v-config.h
/p2v/stamp-test-virt-p2v-pxe-data-files
/p2v/stamp-test-virt-p2v-pxe-hostkey
@@ -457,6 +458,7 @@ Makefile.in
/p2v/virt-p2v.1
/p2v/virt-p2v.i686
/p2v/virt-p2v.img
+/p2v/virt-p2v-kernel-config.pod
/p2v/virt-p2v-make-disk
/p2v/virt-p2v-make-disk.1
/p2v/virt-p2v-make-kickstart
diff --git a/generator/main.ml b/generator/main.ml
index ecc551f72..72f31ecab 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -367,6 +367,10 @@ Run it from the top source directory using the command
P2v_config.generate_p2v_config_h;
output_to "p2v/config.c"
P2v_config.generate_p2v_config_c;
+ output_to "p2v/kernel-config.c"
+ P2v_config.generate_p2v_kernel_config_c;
+ output_to "p2v/virt-p2v-kernel-config.pod"
+ P2v_config.generate_p2v_kernel_config_pod;
(* Generate the list of files generated -- last. *)
printf "generated %d lines of code\n" (get_lines_generated ());
diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml
index e0347d6c2..11aec5ee3 100644
--- a/generator/p2v_config.ml
+++ b/generator/p2v_config.ml
@@ -26,7 +26,7 @@ open Pr
let generate_header = generate_header
~inputs:["generator/p2v_config.ml"]
-type enum_choice = string * string (* name, comment *)
+type enum_choice = string * string * string (* name, cmdline, comment *)
type enum = string * enum_choice list
type config_entry @@ -39,17 +39,22 @@ type config_entry | ConfigStringList
of string
| ConfigSection of string * config_entry list
+type manual_entry = {
+ shortopt : string;
+ description : string;
+}
+
(* Enums. *)
let enums = [
"basis", [
- "BASIS_UNKNOWN", "RTC could not be read";
- "BASIS_UTC", "RTC is either UTC or an offset from
UTC";
- "BASIS_LOCALTIME", "RTC is localtime";
+ "BASIS_UNKNOWN", "unknown", "RTC could not be
read";
+ "BASIS_UTC", "utc", "RTC is either UTC
or an offset from UTC";
+ "BASIS_LOCALTIME", "localtime", "RTC is
localtime";
];
"output_allocation", [
- "OUTPUT_ALLOCATION_NONE", "output allocation not
set";
- "OUTPUT_ALLOCATION_SPARSE", "sparse";
- "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated";
+ "OUTPUT_ALLOCATION_NONE", "none", "output
allocation not set";
+ "OUTPUT_ALLOCATION_SPARSE", "sparse",
"sparse";
+ "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated",
"preallocated";
];
]
@@ -99,6 +104,245 @@ let fields = [
]);
]
+(* Some /proc/cmdline p2v.* options were renamed when we introduced
+ * the generator. This map creates backwards compatibility mappings
+ * for these.
+ *)
+let cmdline_aliases = [
+ "p2v.remote.server", ["p2v.server"];
+ "p2v.remote.port", ["p2v.port"];
+ "p2v.auth.username", ["p2v.username"];
+ "p2v.auth.password", ["p2v.password"];
+ "p2v.auth.identity.url", ["p2v.identity"];
+ "p2v.auth.sudo", ["p2v.sudo"];
+ "p2v.guestname", ["p2v.name"];
+ "p2v.network_map", ["p2v.network"];
+ "p2v.output.type", ["p2v.o"];
+ "p2v.output.allocation", ["p2v.oa"];
+ "p2v.output.connection", ["p2v.oc"];
+ "p2v.output.format", ["p2v.of"];
+ "p2v.output.storage", ["p2v.os"];
+]
+
+(* Some config entries are not exposed on the kernel command line. *)
+let cmdline_ignore = [
+ "p2v.auth.identity.file";
+ "p2v.auth.identity.file_needs_update";
+]
+
+(* Man page snippets for each kernel command line setting. *)
+let cmdline_manual = [
+ "p2v.remote.server", {
+ shortopt = "SERVER";
+ description = "
+The name or IP address of the conversion server.
+
+This is always required if you are using the kernel configuration
+method. If virt-p2v does not find this on the kernel command line
+then it switches to the GUI (interactive) configuration method.";
+ };
+ "p2v.remote.port", {
+ shortopt = "PORT";
+ description = "
+The SSH port number on the conversion server (default: C<22>).";
+ };
+ "p2v.auth.username", {
+ shortopt = "USERNAME";
+ description = "
+The SSH username that we log in as on the conversion server
+(default: C<root>).";
+ };
+ "p2v.auth.password", {
+ shortopt = "PASSWORD";
+ description = "
+The SSH password that we use to log in to the conversion server.
+
+The default is to try with no password. If this fails then virt-p2v
+will ask the user to type the password (probably several times during
+conversion).
+
+This setting is ignored if C<p2v.auth.identity.url> is present.";
+ };
+ "p2v.auth.identity.url", {
+ shortopt = "URL";
+ description = "
+Provide a URL pointing to an SSH identity (private key) file. The URL
+is interpreted by L<curl(1)> so any URL that curl supports can be used
+here, including C<https://> and C<file://>. For more information
on
+using SSH identities, see L</SSH IDENTITIES> below.
+
+If C<p2v.auth.identity.url> is present, it overrides
C<p2v.auth.password>.
+There is no fallback.";
+ };
+ "p2v.auth.sudo", {
+ shortopt = ""; (* ignored for booleans *)
+ description = "
+Use C<p2v.sudo> to tell virt-p2v to use L<sudo(8)> to gain root
+privileges on the conversion server after logging in as a non-root
+user (default: do not use sudo).";
+ };
+ "p2v.guestname", {
+ shortopt = "GUESTNAME";
+ description = "
+The name of the guest that is created. The default is to try to
+derive a name from the physical machine’s hostname (if possible) else
+use a randomly generated name.";
+ };
+ "p2v.vcpus", {
+ shortopt = "N";
+ description = "
+The number of virtual CPUs to give to the guest. The default is to
+use the same as the number of physical CPUs.";
+ };
+ "p2v.memory", {
+ shortopt = "n(M|G)";
+ description = "
+The size of the guest memory. You must specify the unit such as
+megabytes or gigabytes by using for example C<p2v.memory=1024M> or
+C<p2v.memory=1G>.
+
+The default is to use the same amount of RAM as on the physical
+machine.";
+ };
+ "p2v.cpu.vendor", {
+ shortopt = "VENDOR";
+ description = "
+The vCPU vendor, eg. \"Intel\" or \"AMD\". The default is
to use
+the same CPU vendor as the physical machine.";
+ };
+ "p2v.cpu.model", {
+ shortopt = "MODEL";
+ description = "
+The vCPU model, eg. \"IvyBridge\". The default is to use the same
+CPU model as the physical machine.";
+ };
+ "p2v.cpu.sockets", {
+ shortopt = "N";
+ description = "
+Number of vCPU sockets to use. The default is to use the same as the
+physical machine.";
+ };
+ "p2v.cpu.cores", {
+ shortopt = "N";
+ description = "
+Number of vCPU cores to use. The default is to use the same as the
+physical machine.";
+ };
+ "p2v.cpu.threads", {
+ shortopt = "N";
+ description = "
+Number of vCPU hyperthreads to use. The default is to use the same
+as the physical machine.";
+ };
+ "p2v.cpu.acpi", {
+ shortopt = ""; (* ignored for booleans *)
+ description = "
+Whether to enable ACPI in the remote virtual machine. The default is
+to use the same as the physical machine.";
+ };
+ "p2v.cpu.apic", {
+ shortopt = ""; (* ignored for booleans *)
+ description = "
+Whether to enable APIC in the remote virtual machine. The default is
+to use the same as the physical machine.";
+ };
+ "p2v.cpu.pae", {
+ shortopt = ""; (* ignored for booleans *)
+ description = "
+Whether to enable PAE in the remote virtual machine. The default is
+to use the same as the physical machine.";
+ };
+ "p2v.rtc.basis", {
+ shortopt = ""; (* ignored for enums. *)
+ description = "
+Set the basis of the Real Time Clock in the virtual machine. The
+default is to try to detect this setting from the physical machine.";
+ };
+ "p2v.rtc.offset", {
+ shortopt = "[+|-]HOURS";
+ description = "
+The offset of the Real Time Clock from UTC. The default is to try
+to detect this setting from the physical machine.";
+ };
+ "p2v.disks", {
+ shortopt = "sda,sdb,...";
+ description = "
+A list of physical hard disks to convert, for example:
+
+ p2v.disks=sda,sdc
+
+The default is to convert all local hard disks that are found.";
+ };
+ "p2v.removable", {
+ shortopt = "sra,srb,...";
+ description = "
+A list of removable media to convert. The default is to create
+virtual removable devices for every physical removable device found.
+Note that the content of removable media is never copied over.";
+ };
+ "p2v.interfaces", {
+ shortopt = "em1,...";
+ description = "
+A list of network interfaces to convert. The default is to create
+virtual network interfaces for every physical network interface found.";
+ };
+ "p2v.network_map", {
+ shortopt = "interface:target,...";
+ description = "
+Controls how network interfaces are connected to virtual networks on
+the target hypervisor. The default is to connect all network
+interfaces to the target C<default> network.
+
+You give a comma-separated list of C<interface:target> pairs, plus
+optionally a default target. For example:
+
+ p2v.network=em1:ovirtmgmt
+
+maps interface C<em1> to target network C<ovirtmgmt>.
+
+ p2v.network=em1:ovirtmgmt,em2:management,other
+
+maps interface C<em1> to C<ovirtmgmt>, and C<em2> to
C<management>,
+and any other interface that is found to C<other>.";
+ };
+ "p2v.output.type", {
+ shortopt = "(libvirt|local|...)";
+ description = "
+Set the output mode. This is the same as the virt-v2v I<-o> option.
+See L<virt-v2v(1)/OPTIONS>.
+
+If not specified, the default is C<local>, and the converted guest is
+written to F</var/tmp>.";
+ };
+ "p2v.output.allocation", {
+ shortopt = ""; (* ignored for enums *)
+ description = "
+Set the output allocation mode. This is the same as the virt-v2v
+I<-oa> option. See L<virt-v2v(1)/OPTIONS>.";
+ };
+ "p2v.output.connection", {
+ shortopt = "URI";
+ description = "
+Set the output connection libvirt URI. This is the same as the
+virt-v2v I<-oc> option. See L<virt-v2v(1)/OPTIONS> and
+L<http://libvirt.org/uri.html>";
+ };
+ "p2v.output.format", {
+ shortopt = "(raw|qcow2|...)";
+ description = "
+Set the output format. This is the same as the virt-v2v I<-of>
+option. See L<virt-v2v(1)/OPTIONS>.";
+ };
+ "p2v.output.storage", {
+ shortopt = "STORAGE";
+ description = "
+Set the output storage. This is the same as the virt-v2v I<-os>
+option. See L<virt-v2v(1)/OPTIONS>.
+
+If not specified, the default is F</var/tmp> (on the conversion
server).";
+ };
+]
+
let name_of_config_entry = function
| ConfigString n
| ConfigInt (n, _)
@@ -126,7 +370,7 @@ let rec generate_p2v_config_h () fun (name, fields)
->
pr "enum %s {\n" name;
List.iter (
- fun (n, comment) ->
+ fun (n, _, comment) ->
pr " %-25s /* %s */\n" (n ^ ",") comment
) fields;
pr "};\n";
@@ -256,9 +500,9 @@ pr "\
pr "{\n";
pr " switch (v) {\n";
List.iter (
- fun (n, comment) ->
+ fun (n, cmdline, _) ->
pr " case %s:\n" n;
- pr " fprintf (fp, \"%s\");\n" comment;
+ pr " fprintf (fp, \"%s\");\n" cmdline;
pr " break;\n";
) fields;
pr " }\n";
@@ -395,3 +639,197 @@ and generate_field_print prefix v fields let v =
sprintf "%s%s." v n in
generate_field_print (Some printable_name) v fields
) fields
+
+let rec generate_p2v_kernel_config_c () + generate_header CStyle GPLv2plus;
+
+ pr "\
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
+#include <error.h>
+
+#include \"xstrtol.h\"
+
+#include \"p2v.h\"
+#include \"p2v-config.h\"
+
+/**
+ * Read the kernel command line and parse out any C<p2v.*> fields that
+ * we understand into the config struct.
+ */
+void
+update_config_from_kernel_cmdline (struct config *c, char **cmdline)
+{
+ const char *p;
+ strtol_error xerr;
+ unsigned long long ull;
+
+";
+
+ generate_field_config "p2v" "c->" fields;
+
+ pr " if (c->auth.identity.url != NULL)
+ c->auth.identity.file_needs_update = 1;
+
+ /* Undocumented command line parameter used for testing command line
+ * parsing.
+ */
+ p = get_cmdline_key (cmdline, \"p2v.dump_config_and_exit\");
+ if (p) {
+ print_config (c, stdout);
+ exit (EXIT_SUCCESS);
+ }
+}
+"
+
+and generate_field_config prefix v fields + List.iter (
+ function
+ | ConfigSection (n, fields) ->
+ let prefix = sprintf "%s.%s" prefix n in
+ let v = sprintf "%s%s." v n in
+ generate_field_config prefix v fields
+
+ | field ->
+ let n = name_of_config_entry field in
+ let key = sprintf "%s.%s" prefix n in
+
+ if not (List.mem key cmdline_ignore) then (
+ (* Is there an alias for this field? *)
+ let aliases + try List.assoc key cmdline_aliases
+ with Not_found -> [] in
+
+ pr " if ((p = get_cmdline_key (cmdline, \"%s\")) !=
NULL" key;
+ List.iter (
+ fun alias ->
+ pr " ||\n";
+ pr " (p = get_cmdline_key (cmdline, \"%s\")) !=
NULL" alias;
+ ) aliases;
+ pr ") {\n";
+
+ (* Parse the field. *)
+ (match field with
+ | ConfigString n ->
+ pr " free (%s%s);\n" v n;
+ pr " %s%s = strdup (p);\n" v n;
+ pr " if (%s%s == NULL)\n" v n;
+ pr " error (EXIT_FAILURE, errno,
\"strdup\");\n"
+ | ConfigStringList n ->
+ pr " guestfs_int_free_string_list (%s%s);\n" v n;
+ pr " %s%s = guestfs_int_split_string (',',
p);\n" v n;
+ pr " if (%s%s == NULL)\n" v n;
+ pr " error (EXIT_FAILURE, errno,
\"strdup\");\n"
+ | ConfigInt (n, _) ->
+ pr " if (sscanf (p, \"%%d\", &%s%s) !=
1)\n" v n;
+ pr " error (EXIT_FAILURE, errno,\n";
+ pr " \"cannot parse %%s=%%s from the kernel
command line\",\n";
+ pr " %S, p);\n" key
+ | ConfigUnsigned n ->
+ pr " if (sscanf (p, \"%%u\", &%s%s) !=
1)\n" v n;
+ pr " error (EXIT_FAILURE, errno,\n";
+ pr " \"cannot parse %%s=%%s from the kernel
command line\",\n";
+ pr " %S, p);\n" key
+ | ConfigUInt64 n ->
+ pr " xerr = xstrtoull (p, NULL, 0, &ull,
\"0kKMGTPEZY\");\n";
+ pr " if (xerr != LONGINT_OK)\n";
+ pr " error (EXIT_FAILURE, 0,\n";
+ pr " \"cannot parse %%s=%%s from the kernel
command line\",\n";
+ pr " %S, p);\n" key;
+ pr " %s%s = ull;\n" v n
+ | ConfigEnum (n, enum) ->
+ let enum_choices + try List.assoc enum enums
+ with Not_found -> failwithf "cannot find ConfigEnum
%s" enum in
+ pr " ";
+ List.iter (
+ fun (name, cmdline, _) ->
+ pr "if (STREQ (p, \"%s\"))\n" cmdline;
+ pr " %s%s = %s;\n" v n name;
+ pr " else ";
+ ) enum_choices;
+ pr "{\n";
+ pr " error (EXIT_FAILURE, 0,\n";
+ pr " \"invalid value %%s=%%s from the kernel
command line\",\n";
+ pr " %S, p);\n" key;
+ pr " }\n"
+ | ConfigBool n ->
+ pr " %s%s = guestfs_int_is_true (p) || STREQ (p,
\"\");\n" v n
+
+ | ConfigSection _ -> assert false (* see above *)
+ );
+
+ pr " }\n";
+ pr "\n";
+ )
+ ) fields
+
+let rec generate_p2v_kernel_config_pod () + generate_field_config_pod
"p2v" fields
+
+and generate_field_config_pod prefix fields + List.iter (
+ function
+ | ConfigSection (n, fields) ->
+ let prefix = sprintf "%s.%s" prefix n in
+ generate_field_config_pod prefix fields
+
+ | field ->
+ let n = name_of_config_entry field in
+ let key = sprintf "%s.%s" prefix n in
+
+ if not (List.mem key cmdline_ignore) then (
+ let manual_entry + try List.assoc key cmdline_manual
+ with Not_found ->
+ failwithf "generator/p2v_config.ml: missing manual entry for
%s"
+ key in
+
+ (* For booleans there is no shortopt field. For enums
+ * we generate it.
+ *)
+ let shortopt + match field with
+ | ConfigBool _ ->
+ assert (manual_entry.shortopt = "");
+ ""
+ | ConfigEnum (_, enum) ->
+ assert (manual_entry.shortopt = "");
+
+ let enum_choices + try List.assoc enum enums
+ with Not_found -> failwithf "cannot find ConfigEnum
%s" enum in
+ "=(" ^
+ String.concat "|"
+ (List.map (fun (_, cmdline, _) -> cmdline)
+ enum_choices) ^
+ ")"
+ | ConfigString _
+ | ConfigInt _
+ | ConfigUnsigned _
+ | ConfigUInt64 _
+ | ConfigStringList _
+ | ConfigSection _ -> "=" ^ manual_entry.shortopt in
+
+ (* The description must not end with \n *)
+ if String.is_suffix manual_entry.description "\n" then
+ failwithf "generator/p2v_config.ml: description of %s must not
end with \\n"
+ key;
+
+ (* Is there an alias for this field? *)
+ let aliases + try List.assoc key cmdline_aliases
+ with Not_found -> [] in
+ List.iter (
+ fun k -> pr "=item B<%s%s>\n\n" k shortopt
+ ) (key :: aliases);
+
+ pr "%s\n\n" manual_entry.description
+ )
+ ) fields
diff --git a/generator/p2v_config.mli b/generator/p2v_config.mli
index 55d0363a3..43a02e5f1 100644
--- a/generator/p2v_config.mli
+++ b/generator/p2v_config.mli
@@ -18,3 +18,5 @@
val generate_p2v_config_h : unit -> unit
val generate_p2v_config_c : unit -> unit
+val generate_p2v_kernel_config_c : unit -> unit
+val generate_p2v_kernel_config_pod : unit -> unit
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
index f66c2a09b..cfdec535d 100644
--- a/p2v/Makefile.am
+++ b/p2v/Makefile.am
@@ -20,7 +20,9 @@ include $(top_srcdir)/subdir-rules.mk
generator_built = \
about-authors.c \
config.c \
- p2v-config.h
+ kernel-config.c \
+ p2v-config.h \
+ virt-p2v-kernel-config.pod
BUILT_SOURCES = \
$(generator_built)
@@ -89,6 +91,7 @@ virt_p2v_SOURCES = \
inhibit.c \
kernel.c \
kernel-cmdline.c \
+ kernel-config.c \
main.c \
nbd.c \
p2v.h \
@@ -165,10 +168,11 @@ noinst_DATA = \
virt-p2v.1 $(top_builddir)/website/virt-p2v.1.html: stamp-virt-p2v.pod
-stamp-virt-p2v.pod: virt-p2v.pod
+stamp-virt-p2v.pod: virt-p2v.pod virt-p2v-kernel-config.pod
$(PODWRAPPER) \
--man virt-p2v.1 \
--html $(top_builddir)/website/virt-p2v.1.html \
+ --insert $(srcdir)/virt-p2v-kernel-config.pod:__KERNEL_CONFIG__ \
--license GPLv2+ \
--warning safe \
$<
diff --git a/p2v/kernel.c b/p2v/kernel.c
index 4f999755e..33fff0356 100644
--- a/p2v/kernel.c
+++ b/p2v/kernel.c
@@ -42,160 +42,6 @@
static void notify_ui_callback (int type, const char *data);
static void run_command (const char *stage, const char *command);
-void
-update_config_from_kernel_cmdline (struct config *config, char **cmdline)
-{
- const char *p;
-
- p = get_cmdline_key (cmdline, "p2v.server");
- if (p) {
- free (config->remote.server);
- config->remote.server = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.port");
- if (p) {
- if (sscanf (p, "%d", &config->remote.port) != 1)
- error (EXIT_FAILURE, 0,
- "cannot parse p2v.port from kernel command line");
- }
-
- p = get_cmdline_key (cmdline, "p2v.username");
- if (p) {
- free (config->auth.username);
- config->auth.username = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.password");
- if (p) {
- free (config->auth.password);
- config->auth.password = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.identity");
- if (p) {
- free (config->auth.identity.url);
- config->auth.identity.url = strdup (p);
- config->auth.identity.file_needs_update = 1;
- }
-
- p = get_cmdline_key (cmdline, "p2v.sudo");
- if (p)
- config->auth.sudo = 1;
-
- p = get_cmdline_key (cmdline, "p2v.name");
- if (p) {
- free (config->guestname);
- config->guestname = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.vcpus");
- if (p) {
- if (sscanf (p, "%d", &config->vcpus) != 1)
- error (EXIT_FAILURE, 0,
- "cannot parse p2v.vcpus from kernel command line");
- }
-
- p = get_cmdline_key (cmdline, "p2v.memory");
- if (p) {
- char mem_code;
-
- if (sscanf (p, "%" SCNu64 "%c", &config->memory,
&mem_code) != 2)
- error (EXIT_FAILURE, 0,
- "cannot parse p2v.memory from kernel command line");
- config->memory *= 1024;
- if (mem_code == 'M' || mem_code == 'm'
- || mem_code == 'G' || mem_code == 'g')
- config->memory *= 1024;
- if (mem_code == 'G' || mem_code == 'g')
- config->memory *= 1024;
- if (mem_code != 'M' && mem_code != 'm'
- && mem_code != 'G' && mem_code != 'g')
- error (EXIT_FAILURE, 0,
- "p2v.memory on kernel command line must be followed by
'G' or 'M'");
- }
-
- p = get_cmdline_key (cmdline, "p2v.disks");
- if (p) {
- CLEANUP_FREE char *t;
-
- t = strdup (p);
- guestfs_int_free_string_list (config->disks);
- config->disks = guestfs_int_split_string (',', t);
- }
-
- p = get_cmdline_key (cmdline, "p2v.removable");
- if (p) {
- CLEANUP_FREE char *t;
-
- t = strdup (p);
- guestfs_int_free_string_list (config->removable);
- config->removable = guestfs_int_split_string (',', t);
- }
-
- p = get_cmdline_key (cmdline, "p2v.interfaces");
- if (p) {
- CLEANUP_FREE char *t;
-
- t = strdup (p);
- guestfs_int_free_string_list (config->interfaces);
- config->interfaces = guestfs_int_split_string (',', t);
- }
-
- p = get_cmdline_key (cmdline, "p2v.network");
- if (p) {
- CLEANUP_FREE char *t;
-
- t = strdup (p);
- guestfs_int_free_string_list (config->network_map);
- config->network_map = guestfs_int_split_string (',', t);
- }
-
- p = get_cmdline_key (cmdline, "p2v.o");
- if (p) {
- free (config->output.type);
- config->output.type = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.oa");
- if (p) {
- if (STREQ (p, "sparse"))
- config->output.allocation = OUTPUT_ALLOCATION_SPARSE;
- else if (STREQ (p, "preallocated"))
- config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED;
- else
- fprintf (stderr, "%s: warning: don't know what p2v.oa=%s
means\n",
- getprogname (), p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.oc");
- if (p) {
- free (config->output.connection);
- config->output.connection = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.of");
- if (p) {
- free (config->output.format);
- config->output.format = strdup (p);
- }
-
- p = get_cmdline_key (cmdline, "p2v.os");
- if (p) {
- free (config->output.storage);
- config->output.storage = strdup (p);
- }
-
- /* Undocumented command line parameter used for testing command line
- * parsing.
- */
- p = get_cmdline_key (cmdline, "p2v.dump_config_and_exit");
- if (p) {
- print_config (config, stdout);
- exit (EXIT_SUCCESS);
- }
-}
-
/* Perform conversion using the kernel method. */
void
kernel_conversion (struct config *config, char **cmdline, int cmdline_source)
diff --git a/p2v/p2v.h b/p2v/p2v.h
index 021ea2946..ee661514c 100644
--- a/p2v/p2v.h
+++ b/p2v/p2v.h
@@ -74,8 +74,10 @@ extern const char *get_cmdline_key (char **cmdline, const
char *key);
#define CMDLINE_SOURCE_COMMAND_LINE 1 /* --cmdline */
#define CMDLINE_SOURCE_PROC_CMDLINE 2 /* /proc/cmdline */
-/* kernel.c */
+/* kernel-config.c */
extern void update_config_from_kernel_cmdline (struct config *config, char
**cmdline);
+
+/* kernel.c */
extern void kernel_conversion (struct config *, char **cmdline, int
cmdline_source);
/* gui.c */
diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
index fc2e7d310..48548f8c6 100644
--- a/p2v/virt-p2v.pod
+++ b/p2v/virt-p2v.pod
@@ -302,136 +302,7 @@ You have to set some or all of the following command line
arguments:
=over 4
-=item B<p2v.server=SERVER>
-
-The name or IP address of the conversion server.
-
-This is always required if you are using the kernel configuration
-method. If virt-p2v does not find this on the kernel command line
-then it switches to the GUI (interactive) configuration method.
-
-=item B<p2v.port=NN>
-
-The SSH port number on the conversion server (default: C<22>).
-
-=item B<p2v.username=USERNAME>
-
-The SSH username that we log in as on the conversion server
-(default: C<root>).
-
-=item B<p2v.password=PASSWORD>
-
-The SSH password that we use to log in to the conversion server.
-
-The default is to try with no password. If this fails then virt-p2v
-will ask the user to type the password (probably several times during
-conversion).
-
-This setting is ignored if C<p2v.identity> is present.
-
-=item B<p2v.identity=URL>
-
-Provide a URL pointing to an SSH identity (private key) file. The URL
-is interpreted by L<curl(1)> so any URL that curl supports can be used
-here, including C<https://> and C<file://>. For more information
on
-using SSH identities, see L</SSH IDENTITIES> below.
-
-If C<p2v.identity> is present, it overrides C<p2v.password>. There
is
-no fallback.
-
-=item B<p2v.sudo>
-
-Use C<p2v.sudo> to tell virt-p2v to use L<sudo(8)> to gain root
-privileges on the conversion server after logging in as a non-root
-user (default: do not use sudo).
-
-=item B<p2v.name=GUESTNAME>
-
-The name of the guest that is created. The default is to try to
-derive a name from the physical machine’s hostname (if possible) else
-use a randomly generated name.
-
-=item B<p2v.vcpus=NN>
-
-The number of virtual CPUs to give to the guest. The default is to
-use the same as the number of physical CPUs.
-
-=item B<p2v.memory=NN(M|G)>
-
-The size of the guest memory. You must specify the unit as either
-megabytes or gigabytes by using (eg) C<p2v.memory=1024M> or
-C<p2v.memory=1G>.
-
-The default is to use the same amount of RAM as on the physical
-machine.
-
-=item B<p2v.disks=sdX,sdY,..>
-
-A list of physical hard disks to convert, for example:
-
- p2v.disks=sda,sdc
-
-The default is to convert all local hard disks that are found.
-
-=item B<p2v.removable=srX,srY,..>
-
-A list of removable media to convert. The default is to create
-virtual removable devices for every physical removable device found.
-Note that the content of removable media is never copied over.
-
-=item B<p2v.interfaces=em1,..>
-
-A list of network interfaces to convert. The default is to create
-virtual network interfaces for every physical network interface found.
-
-=item B<p2v.network=interface:target,...>
-
-Controls how network interfaces are connected to virtual networks on
-the target hypervisor. The default is to connect all network
-interfaces to the target C<default> network.
-
-You give a comma-separated list of C<interface:target> pairs, plus
-optionally a default target. For example:
-
- p2v.network=em1:ovirtmgmt
-
-maps interface C<em1> to target network C<ovirtmgmt>.
-
- p2v.network=em1:ovirtmgmt,em2:management,other
-
-maps interface C<em1> to C<ovirtmgmt>, and C<em2> to
C<management>,
-and any other interface that is found to C<other>.
-
-=item B<p2v.o=[libvirt|local|...]>
-
-Set the output mode. This is the same as the virt-v2v I<-o> option.
-See L<virt-v2v(1)/OPTIONS>.
-
-If not specified, the default is C<local>, and the converted guest is
-written to F</var/tmp>.
-
-=item B<p2v.oa=sparse|preallocated>
-
-Set the output allocation mode. This is the same as the virt-v2v
-I<-oa> option. See L<virt-v2v(1)/OPTIONS>.
-
-=item B<p2v.oc=...>
-
-Set the output connection libvirt URI. This is the same as the
-virt-v2v I<-oc> option. See L<virt-v2v(1)/OPTIONS> and
-L<http://libvirt.org/uri.html>
-
-=item B<p2v.of=raw|qcow2|...>
-
-Set the output format. This is the same as the virt-v2v I<-of>
-option. See L<virt-v2v(1)/OPTIONS>.
-
-=item B<p2v.os=...>
-
-Set the output storage. This is the same as the virt-v2v I<-os>
-option. See L<virt-v2v(1)/OPTIONS>.
-
-If not specified, the default is F</var/tmp> (on the conversion server).
+__KERNEL_CONFIG__
=item B<p2v.pre=COMMAND>
diff --git a/po-docs/language.mk b/po-docs/language.mk
index 3eeb058e0..0163edab3 100644
--- a/po-docs/language.mk
+++ b/po-docs/language.mk
@@ -148,6 +148,14 @@ virt-sysprep.1: virt-sysprep.pod sysprep-extra-options.pod
sysprep-operations.po
--insert $(srcdir)/sysprep-operations.pod:__OPERATIONS__ \
$<
+virt-p2v.1: virt-p2v.pod virt-p2v-kernel-config.pod
+ $(PODWRAPPER) \
+ --no-strict-checks \
+ --man $@ \
+ --license GPLv2+ \
+ --insert $(srcdir)/virt-p2v-kernel-config.pod:__KERNEL_CONFIG__ \
+ $<
+
%.1: %.pod
$(PODWRAPPER) \
--no-strict-checks \
diff --git a/po-docs/podfiles b/po-docs/podfiles
index 31a3aca3a..b6bd39b68 100644
--- a/po-docs/podfiles
+++ b/po-docs/podfiles
@@ -53,6 +53,7 @@
../lua/examples/guestfs-lua.pod
../make-fs/virt-make-fs.pod
../ocaml/examples/guestfs-ocaml.pod
+../p2v/virt-p2v-kernel-config.pod
../p2v/virt-p2v-make-disk.pod
../p2v/virt-p2v-make-kickstart.pod
../p2v/virt-p2v-make-kiwi.pod
--
2.17.1
Maybe Matching Threads
- [PATCH 0/6] p2v: start making it independent
- [PATCH 1/6] p2v: move kernel config to perl script
- [PATCH 0/2] Remove virt-p2v from libguestfs
- [p2v PATCH 00/11] Expose virt-v2v's "-oo"; re-enable openstack
- [p2v PATCH 02/11] Introduce "p2v.output.misc" for passing "-oo" options to virt-v2v