From 3d70900bac450c874fdddaadfd1aed9f55d8cfff Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 21 Mar 2017 17:02:08 +0000 Subject: [PATCH] p2v: Move code to generate physical XML to a separate file. This is pure refactoring, except that I have removed the definition xmlBufferDetach since that function is not used. --- p2v/Makefile.am | 1 + p2v/conversion.c | 356 +-------------------------------------------- p2v/p2v.h | 9 ++ p2v/physical-xml.c | 352 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+), 351 deletions(-) create mode 100644 p2v/physical-xml.c diff --git a/p2v/Makefile.am b/p2v/Makefile.am index 5f90aa728..726916027 100644 --- a/p2v/Makefile.am +++ b/p2v/Makefile.am @@ -84,6 +84,7 @@ virt_p2v_SOURCES = \ main.c \ nbd.c \ p2v.h \ + physical-xml.c \ rtc.c \ ssh.c \ utils.c \ diff --git a/p2v/conversion.c b/p2v/conversion.c index e7e7ce039..57b83b9c4 100644 --- a/p2v/conversion.c +++ b/p2v/conversion.c @@ -49,52 +49,16 @@ #include -#include - -#include - #include "ignore-value.h" #include "getprogname.h" #include "miniexpect.h" #include "p2v.h" -#ifndef HAVE_XMLBUFFERDETACH -/* Added in libxml2 2.8.0. This is mostly a copy of the function from - * upstream libxml2, which is under a more permissive license. - */ -static xmlChar * -xmlBufferDetach (xmlBufferPtr buf) -{ - xmlChar *ret; - - if (buf == NULL) - return NULL; - if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) - return NULL; - - ret = buf->content; - buf->content = NULL; - buf->size = 0; - buf->use = 0; - - return ret; -} -#endif - -/* Data per NBD connection / physical disk. */ -struct data_conn { - mexp_h *h; /* miniexpect handle to ssh */ - pid_t nbd_pid; /* NBD server PID */ - int nbd_remote_port; /* remote NBD port on conversion server */ -}; - static void cleanup_data_conns (struct data_conn *data_conns, size_t nr); static void generate_name (struct config *, const char *filename); -static void generate_libvirt_xml (struct config *, struct data_conn *, const char *filename); static void generate_wrapper_script (struct config *, const char *remote_dir, const char *filename); static void generate_system_data (const char *dmesg_file, const char *lscpu_file, const char *lspci_file, const char *lsscsi_file, const char *lsusb_file); -static const char *map_interface_to_network (struct config *, const char *interface); static void print_quoted (FILE *fp, const char *s); static char *conversion_error; @@ -199,7 +163,7 @@ start_conversion (struct config *config, CLEANUP_FREE char *remote_dir = NULL; char tmpdir[] = "/tmp/p2v.XXXXXX"; char name_file[] = "/tmp/p2v.XXXXXX/name"; - char libvirt_xml_file[] = "/tmp/p2v.XXXXXX/physical.xml"; + char physical_xml_file[] = "/tmp/p2v.XXXXXX/physical.xml"; char wrapper_script[] = "/tmp/p2v.XXXXXX/virt-v2v-wrapper.sh"; char dmesg_file[] = "/tmp/p2v.XXXXXX/dmesg"; char lscpu_file[] = "/tmp/p2v.XXXXXX/lscpu"; @@ -335,7 +299,7 @@ start_conversion (struct config *config, exit (EXIT_FAILURE); } memcpy (name_file, tmpdir, strlen (tmpdir)); - memcpy (libvirt_xml_file, tmpdir, strlen (tmpdir)); + memcpy (physical_xml_file, tmpdir, strlen (tmpdir)); memcpy (wrapper_script, tmpdir, strlen (tmpdir)); memcpy (dmesg_file, tmpdir, strlen (tmpdir)); memcpy (lscpu_file, tmpdir, strlen (tmpdir)); @@ -345,7 +309,7 @@ start_conversion (struct config *config, /* Generate the static files. */ generate_name (config, name_file); - generate_libvirt_xml (config, data_conns, libvirt_xml_file); + generate_physical_xml (config, data_conns, physical_xml_file); generate_wrapper_script (config, remote_dir, wrapper_script); generate_system_data (dmesg_file, lscpu_file, lspci_file, lsscsi_file, lsusb_file); @@ -367,9 +331,9 @@ start_conversion (struct config *config, name_file, remote_dir, get_ssh_error ()); goto out; } - if (scp_file (config, libvirt_xml_file, remote_dir) == -1) { + if (scp_file (config, physical_xml_file, remote_dir) == -1) { set_conversion_error ("scp: %s to %s: %s", - libvirt_xml_file, remote_dir, get_ssh_error ()); + physical_xml_file, remote_dir, get_ssh_error ()); goto out; } if (scp_file (config, wrapper_script, remote_dir) == -1) { @@ -497,316 +461,6 @@ cleanup_data_conns (struct data_conn *data_conns, size_t nr) } } -/* Macros "inspired" by lib/launch-libvirt.c */ -/* */ -#define end_element() \ - while (0); \ - do { \ - if (xmlTextWriterEndElement (xo) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterEndElement"); \ - } while (0) - -/* */ -#define empty_element(element) \ - do { start_element(element) {} end_element (); } while (0) - -/* key=value attribute of the current element. */ -#define attribute(key,value) \ - do { \ - if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteAttribute"); \ - } while (0) - -/* key=value, but value is a printf-style format string. */ -#define attribute_format(key,fs,...) \ - do { \ - if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ - fs, ##__VA_ARGS__) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatAttribute"); \ - } while (0) - -/* A string, eg. within an element. */ -#define string(str) \ - do { \ - if (xmlTextWriterWriteString (xo, BAD_CAST (str)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteString"); \ - } while (0) - -/* A string, using printf-style formatting. */ -#define string_format(fs,...) \ - do { \ - if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatString"); \ - } while (0) - -/* An XML comment. */ -#define comment(str) \ - do { \ - if (xmlTextWriterWriteComment (xo, BAD_CAST (str)) == -1) \ - error (EXIT_FAILURE, errno, "xmlTextWriterWriteComment"); \ - } while (0) - -/** - * Write the libvirt XML for this physical machine. - * - * Note this is not actually input for libvirt. It's input for - * virt-v2v on the conversion server. Virt-v2v will (if necessary) - * generate the final libvirt XML. - */ -static void -generate_libvirt_xml (struct config *config, struct data_conn *data_conns, - const char *filename) -{ - uint64_t memkb; - CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = NULL; - size_t i; - - xo = xmlNewTextWriterFilename (filename, 0); - if (xo == NULL) - error (EXIT_FAILURE, errno, "xmlNewTextWriterFilename"); - - if (xmlTextWriterSetIndent (xo, 1) == -1 || - xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1) - error (EXIT_FAILURE, errno, "could not set XML indent"); - if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1) - error (EXIT_FAILURE, errno, "xmlTextWriterStartDocument"); - - memkb = config->memory / 1024; - - comment - (" NOTE!\n" - "\n" - " This libvirt XML is generated by the virt-p2v front end, in\n" - " order to communicate with the backend virt-v2v process running\n" - " on the conversion server. It is a minimal description of the\n" - " physical machine. If the target of the conversion is libvirt,\n" - " then virt-v2v will generate the real target libvirt XML, which\n" - " has only a little to do with the XML in this file.\n" - "\n" - " TL;DR: Don't try to load this XML into libvirt. "); - - start_element ("domain") { - attribute ("type", "physical"); - - start_element ("name") { - string (config->guestname); - } end_element (); - - start_element ("memory") { - attribute ("unit", "KiB"); - string_format ("%" PRIu64, memkb); - } end_element (); - - start_element ("currentMemory") { - attribute ("unit", "KiB"); - string_format ("%" PRIu64, memkb); - } end_element (); - - start_element ("vcpu") { - string_format ("%d", config->vcpus); - } end_element (); - - if (config->cpu.vendor || config->cpu.model || - config->cpu.sockets || config->cpu.cores || config->cpu.threads) { - /* https://libvirt.org/formatdomain.html#elementsCPU */ - start_element ("cpu") { - attribute ("match", "minimum"); - if (config->cpu.vendor) { - start_element ("vendor") { - string (config->cpu.vendor); - } end_element (); - } - if (config->cpu.model) { - start_element ("model") { - attribute ("fallback", "allow"); - string (config->cpu.model); - } end_element (); - } - if (config->cpu.sockets || config->cpu.cores || config->cpu.threads) { - start_element ("topology") { - if (config->cpu.sockets) - attribute_format ("sockets", "%u", config->cpu.sockets); - if (config->cpu.cores) - attribute_format ("cores", "%u", config->cpu.cores); - if (config->cpu.threads) - attribute_format ("threads", "%u", config->cpu.threads); - } end_element (); - } - } end_element (); - } - - switch (config->rtc.basis) { - case BASIS_UNKNOWN: - /* Don't emit any element. */ - break; - case BASIS_UTC: - start_element ("clock") { - if (config->rtc.offset == 0) - attribute ("offset", "utc"); - else { - attribute ("offset", "variable"); - attribute ("basis", "utc"); - attribute_format ("adjustment", "%d", config->rtc.offset); - } - } end_element (); - break; - case BASIS_LOCALTIME: - start_element ("clock") { - attribute ("offset", "localtime"); - /* config->rtc.offset is always 0 in this case */ - } end_element (); - break; - } - - start_element ("os") { - start_element ("type") { - attribute ("arch", host_cpu); - string ("hvm"); - } end_element (); - } end_element (); - - start_element ("features") { - if (config->cpu.acpi) empty_element ("acpi"); - if (config->cpu.apic) empty_element ("apic"); - if (config->cpu.pae) empty_element ("pae"); - } end_element (); - - start_element ("devices") { - - for (i = 0; config->disks[i] != NULL; ++i) { - char target_dev[64]; - - if (config->disks[i][0] == '/') { - target_sd: - memcpy (target_dev, "sd", 2); - guestfs_int_drive_name (i, &target_dev[2]); - } else { - if (strlen (config->disks[i]) <= sizeof (target_dev) - 1) - strcpy (target_dev, config->disks[i]); - else - goto target_sd; - } - - start_element ("disk") { - attribute ("type", "network"); - attribute ("device", "disk"); - start_element ("driver") { - attribute ("name", "qemu"); - attribute ("type", "raw"); - } end_element (); - start_element ("source") { - attribute ("protocol", "nbd"); - start_element ("host") { - attribute ("name", "localhost"); - attribute_format ("port", "%d", data_conns[i].nbd_remote_port); - } end_element (); - } end_element (); - start_element ("target") { - attribute ("dev", target_dev); - /* XXX Need to set bus to "ide" or "scsi" here. */ - } end_element (); - } end_element (); - } - - if (config->removable) { - for (i = 0; config->removable[i] != NULL; ++i) { - start_element ("disk") { - attribute ("type", "network"); - attribute ("device", "cdrom"); - start_element ("driver") { - attribute ("name", "qemu"); - attribute ("type", "raw"); - } end_element (); - start_element ("target") { - attribute ("dev", config->removable[i]); - } end_element (); - } end_element (); - } - } - - if (config->interfaces) { - for (i = 0; config->interfaces[i] != NULL; ++i) { - const char *target_network; - CLEANUP_FREE char *mac_filename = NULL; - CLEANUP_FREE char *mac = NULL; - - target_network = - map_interface_to_network (config, config->interfaces[i]); - - if (asprintf (&mac_filename, "/sys/class/net/%s/address", - config->interfaces[i]) == -1) - error (EXIT_FAILURE, errno, "asprintf"); - if (g_file_get_contents (mac_filename, &mac, NULL, NULL)) { - const size_t len = strlen (mac); - - if (len > 0 && mac[len-1] == '\n') - mac[len-1] = '\0'; - } - - start_element ("interface") { - attribute ("type", "network"); - start_element ("source") { - attribute ("network", target_network); - } end_element (); - start_element ("target") { - attribute ("dev", config->interfaces[i]); - } end_element (); - if (mac) { - start_element ("mac") { - attribute ("address", mac); - } end_element (); - } - } end_element (); - } - } - - } end_element (); /* */ - - } end_element (); /* */ - - if (xmlTextWriterEndDocument (xo) == -1) - error (EXIT_FAILURE, errno, "xmlTextWriterEndDocument"); -} - -/** - * Using Cnetwork_map>, map the interface to a target - * network name. If no map is found, return C. See - * L documentation of C<"p2v.network"> for how the - * network map works. - * - * Note this returns a static string which is only valid as long as - * Cnetwork_map> is not freed. - */ -static const char * -map_interface_to_network (struct config *config, const char *interface) -{ - size_t i, len; - - if (config->network_map == NULL) - return "default"; - - for (i = 0; config->network_map[i] != NULL; ++i) { - /* The default map maps everything. */ - if (strchr (config->network_map[i], ':') == NULL) - return config->network_map[i]; - - /* interface: ? */ - len = strlen (interface); - if (STRPREFIX (config->network_map[i], interface) && - config->network_map[i][len] == ':') - return &config->network_map[i][len+1]; - } - - /* No mapping found. */ - return "default"; -} - /** * Write the guest name into C. */ diff --git a/p2v/p2v.h b/p2v/p2v.h index 38ebe7916..7728282ea 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -136,6 +136,12 @@ extern void kernel_conversion (struct config *, char **cmdline, int cmdline_sour extern void gui_conversion (struct config *); /* conversion.c */ +struct data_conn { /* Data per NBD connection / physical disk. */ + mexp_h *h; /* miniexpect handle to ssh */ + pid_t nbd_pid; /* NBD server PID */ + int nbd_remote_port; /* remote NBD port on conversion server */ +}; + extern int start_conversion (struct config *, void (*notify_ui) (int type, const char *data)); #define NOTIFY_LOG_DIR 1 /* location of remote log directory */ #define NOTIFY_REMOTE_MESSAGE 2 /* log message from remote virt-v2v */ @@ -144,6 +150,9 @@ extern const char *get_conversion_error (void); extern void cancel_conversion (void); extern int conversion_is_running (void); +/* physical-xml.c */ +extern void generate_physical_xml (struct config *, struct data_conn *, const char *filename); + /* inhibit.c */ extern int inhibit_power_saving (void); diff --git a/p2v/physical-xml.c b/p2v/physical-xml.c new file mode 100644 index 000000000..6e81c27c1 --- /dev/null +++ b/p2v/physical-xml.c @@ -0,0 +1,352 @@ +/* virt-p2v + * Copyright (C) 2009-2017 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. + */ + +/** + * Create the F file, which is a piece of phony libvirt + * XML used to communicate the metadata of the physical machine to + * virt-v2v. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "p2v.h" + +static const char *map_interface_to_network (struct config *, const char *interface); + +/* Macros "inspired" by lib/launch-libvirt.c */ +/* */ +#define end_element() \ + while (0); \ + do { \ + if (xmlTextWriterEndElement (xo) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterEndElement"); \ + } while (0) + +/* */ +#define empty_element(element) \ + do { start_element(element) {} end_element (); } while (0) + +/* key=value attribute of the current element. */ +#define attribute(key,value) \ + do { \ + if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterWriteAttribute"); \ + } while (0) + +/* key=value, but value is a printf-style format string. */ +#define attribute_format(key,fs,...) \ + do { \ + if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ + fs, ##__VA_ARGS__) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatAttribute"); \ + } while (0) + +/* A string, eg. within an element. */ +#define string(str) \ + do { \ + if (xmlTextWriterWriteString (xo, BAD_CAST (str)) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterWriteString"); \ + } while (0) + +/* A string, using printf-style formatting. */ +#define string_format(fs,...) \ + do { \ + if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatString"); \ + } while (0) + +/* An XML comment. */ +#define comment(str) \ + do { \ + if (xmlTextWriterWriteComment (xo, BAD_CAST (str)) == -1) \ + error (EXIT_FAILURE, errno, "xmlTextWriterWriteComment"); \ + } while (0) + +/** + * Write the libvirt XML for this physical machine. + * + * Note this is not actually input for libvirt. It's input for + * virt-v2v on the conversion server. Virt-v2v will (if necessary) + * generate the final libvirt XML. + */ +void +generate_physical_xml (struct config *config, struct data_conn *data_conns, + const char *filename) +{ + uint64_t memkb; + CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = NULL; + size_t i; + + xo = xmlNewTextWriterFilename (filename, 0); + if (xo == NULL) + error (EXIT_FAILURE, errno, "xmlNewTextWriterFilename"); + + if (xmlTextWriterSetIndent (xo, 1) == -1 || + xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1) + error (EXIT_FAILURE, errno, "could not set XML indent"); + if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1) + error (EXIT_FAILURE, errno, "xmlTextWriterStartDocument"); + + memkb = config->memory / 1024; + + comment + (" NOTE!\n" + "\n" + " This libvirt XML is generated by the virt-p2v front end, in\n" + " order to communicate with the backend virt-v2v process running\n" + " on the conversion server. It is a minimal description of the\n" + " physical machine. If the target of the conversion is libvirt,\n" + " then virt-v2v will generate the real target libvirt XML, which\n" + " has only a little to do with the XML in this file.\n" + "\n" + " TL;DR: Don't try to load this XML into libvirt. "); + + start_element ("domain") { + attribute ("type", "physical"); + + start_element ("name") { + string (config->guestname); + } end_element (); + + start_element ("memory") { + attribute ("unit", "KiB"); + string_format ("%" PRIu64, memkb); + } end_element (); + + start_element ("currentMemory") { + attribute ("unit", "KiB"); + string_format ("%" PRIu64, memkb); + } end_element (); + + start_element ("vcpu") { + string_format ("%d", config->vcpus); + } end_element (); + + if (config->cpu.vendor || config->cpu.model || + config->cpu.sockets || config->cpu.cores || config->cpu.threads) { + /* https://libvirt.org/formatdomain.html#elementsCPU */ + start_element ("cpu") { + attribute ("match", "minimum"); + if (config->cpu.vendor) { + start_element ("vendor") { + string (config->cpu.vendor); + } end_element (); + } + if (config->cpu.model) { + start_element ("model") { + attribute ("fallback", "allow"); + string (config->cpu.model); + } end_element (); + } + if (config->cpu.sockets || config->cpu.cores || config->cpu.threads) { + start_element ("topology") { + if (config->cpu.sockets) + attribute_format ("sockets", "%u", config->cpu.sockets); + if (config->cpu.cores) + attribute_format ("cores", "%u", config->cpu.cores); + if (config->cpu.threads) + attribute_format ("threads", "%u", config->cpu.threads); + } end_element (); + } + } end_element (); + } + + switch (config->rtc.basis) { + case BASIS_UNKNOWN: + /* Don't emit any element. */ + break; + case BASIS_UTC: + start_element ("clock") { + if (config->rtc.offset == 0) + attribute ("offset", "utc"); + else { + attribute ("offset", "variable"); + attribute ("basis", "utc"); + attribute_format ("adjustment", "%d", config->rtc.offset); + } + } end_element (); + break; + case BASIS_LOCALTIME: + start_element ("clock") { + attribute ("offset", "localtime"); + /* config->rtc.offset is always 0 in this case */ + } end_element (); + break; + } + + start_element ("os") { + start_element ("type") { + attribute ("arch", host_cpu); + string ("hvm"); + } end_element (); + } end_element (); + + start_element ("features") { + if (config->cpu.acpi) empty_element ("acpi"); + if (config->cpu.apic) empty_element ("apic"); + if (config->cpu.pae) empty_element ("pae"); + } end_element (); + + start_element ("devices") { + + for (i = 0; config->disks[i] != NULL; ++i) { + char target_dev[64]; + + if (config->disks[i][0] == '/') { + target_sd: + memcpy (target_dev, "sd", 2); + guestfs_int_drive_name (i, &target_dev[2]); + } else { + if (strlen (config->disks[i]) <= sizeof (target_dev) - 1) + strcpy (target_dev, config->disks[i]); + else + goto target_sd; + } + + start_element ("disk") { + attribute ("type", "network"); + attribute ("device", "disk"); + start_element ("driver") { + attribute ("name", "qemu"); + attribute ("type", "raw"); + } end_element (); + start_element ("source") { + attribute ("protocol", "nbd"); + start_element ("host") { + attribute ("name", "localhost"); + attribute_format ("port", "%d", data_conns[i].nbd_remote_port); + } end_element (); + } end_element (); + start_element ("target") { + attribute ("dev", target_dev); + /* XXX Need to set bus to "ide" or "scsi" here. */ + } end_element (); + } end_element (); + } + + if (config->removable) { + for (i = 0; config->removable[i] != NULL; ++i) { + start_element ("disk") { + attribute ("type", "network"); + attribute ("device", "cdrom"); + start_element ("driver") { + attribute ("name", "qemu"); + attribute ("type", "raw"); + } end_element (); + start_element ("target") { + attribute ("dev", config->removable[i]); + } end_element (); + } end_element (); + } + } + + if (config->interfaces) { + for (i = 0; config->interfaces[i] != NULL; ++i) { + const char *target_network; + CLEANUP_FREE char *mac_filename = NULL; + CLEANUP_FREE char *mac = NULL; + + target_network = + map_interface_to_network (config, config->interfaces[i]); + + if (asprintf (&mac_filename, "/sys/class/net/%s/address", + config->interfaces[i]) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + if (g_file_get_contents (mac_filename, &mac, NULL, NULL)) { + const size_t len = strlen (mac); + + if (len > 0 && mac[len-1] == '\n') + mac[len-1] = '\0'; + } + + start_element ("interface") { + attribute ("type", "network"); + start_element ("source") { + attribute ("network", target_network); + } end_element (); + start_element ("target") { + attribute ("dev", config->interfaces[i]); + } end_element (); + if (mac) { + start_element ("mac") { + attribute ("address", mac); + } end_element (); + } + } end_element (); + } + } + + } end_element (); /* */ + + } end_element (); /* */ + + if (xmlTextWriterEndDocument (xo) == -1) + error (EXIT_FAILURE, errno, "xmlTextWriterEndDocument"); +} + +/** + * Using Cnetwork_map>, map the interface to a target + * network name. If no map is found, return C. See + * L documentation of C<"p2v.network"> for how the + * network map works. + * + * Note this returns a static string which is only valid as long as + * Cnetwork_map> is not freed. + */ +static const char * +map_interface_to_network (struct config *config, const char *interface) +{ + size_t i, len; + + if (config->network_map == NULL) + return "default"; + + for (i = 0; config->network_map[i] != NULL; ++i) { + /* The default map maps everything. */ + if (strchr (config->network_map[i], ':') == NULL) + return config->network_map[i]; + + /* interface: ? */ + len = strlen (interface); + if (STRPREFIX (config->network_map[i], interface) && + config->network_map[i][len] == ':') + return &config->network_map[i][len+1]; + } + + /* No mapping found. */ + return "default"; +}