mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
When using the virt-p2v ISO in command line mode, we did not wait for the network to come online before starting virt-p2v. Therefore virt-p2v could exit with an error when testing the ssh connection (or on the other hand, it might work randomly). If the user logs in and runs 'launch-virt-p2v' by hand, then it would usually work because the network had been brought online in the meantime. Fix this by waiting for NetworkManager to bring the connection online before calling test_connection(). Note that the obvious way to fix this (changing the systemd service to wait for network-online.target) does *not* work - I added a comment to the service about this. Thanks: Tingting Zheng
159 lines
4.0 KiB
C
159 lines
4.0 KiB
C
/* virt-p2v
|
|
* Copyright (C) 2015 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 <ctype.h>
|
|
#include <unistd.h>
|
|
#include <locale.h>
|
|
#include <libintl.h>
|
|
|
|
#include "ignore-value.h"
|
|
|
|
#include "p2v.h"
|
|
|
|
#define CHOMP(line,len) \
|
|
do { \
|
|
if ((len) > 0 && (line)[(len)-1] == '\n') { \
|
|
(line)[(len)-1] = '\0'; \
|
|
len--; \
|
|
} \
|
|
} while (0)
|
|
|
|
/* Return contents of /sys/class/net/<if_name>/address (if found). */
|
|
char *
|
|
get_if_addr (const char *if_name)
|
|
{
|
|
CLEANUP_FCLOSE FILE *fp = NULL;
|
|
CLEANUP_FREE char *path = NULL;
|
|
char *content = NULL;
|
|
size_t len = 0;
|
|
ssize_t n;
|
|
|
|
if (asprintf (&path, "/sys/class/net/%s/address", if_name) == -1) {
|
|
perror ("asprintf");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
fp = fopen (path, "r");
|
|
if (fp == NULL)
|
|
return NULL;
|
|
if ((n = getline (&content, &len, fp)) == -1) {
|
|
perror (path);
|
|
free (content);
|
|
return NULL;
|
|
}
|
|
CHOMP (content, n);
|
|
return content;
|
|
}
|
|
|
|
/* Return contents of /sys/class/net/<if_name>/device/vendor (if found),
|
|
* mapped to the PCI vendor. See:
|
|
* http://pjwelsh.blogspot.co.uk/2011/11/howto-get-network-card-vendor-device-or.html
|
|
*/
|
|
char *
|
|
get_if_vendor (const char *if_name, int truncate)
|
|
{
|
|
CLEANUP_FCLOSE FILE *fp = NULL;
|
|
CLEANUP_FREE char *path = NULL;
|
|
char *line = NULL;
|
|
size_t len = 0;
|
|
ssize_t n;
|
|
char vendor[5];
|
|
|
|
if (asprintf (&path, "/sys/class/net/%s/device/vendor", if_name) == -1) {
|
|
perror ("asprintf");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
fp = fopen (path, "r");
|
|
if (fp == NULL) {
|
|
perror (path);
|
|
return NULL;
|
|
}
|
|
if ((n = getline (&line, &len, fp)) == -1) {
|
|
perror (path);
|
|
free (line);
|
|
return NULL;
|
|
}
|
|
|
|
/* Vendor is (always?) a 16 bit quantity (as defined by PCI),
|
|
* something like "0x8086" (for Intel Corp).
|
|
*/
|
|
CHOMP (line, n);
|
|
if (line[0] != '0' || line[1] != 'x' || strlen (&line[2]) != 4) {
|
|
free (line);
|
|
return NULL;
|
|
}
|
|
|
|
strcpy (vendor, &line[2]);
|
|
|
|
fclose (fp);
|
|
fp = fopen ("/usr/share/hwdata/pci.ids", "r");
|
|
if (fp == NULL) {
|
|
perror ("/usr/share/hwdata/pci.ids");
|
|
free (line);
|
|
return NULL;
|
|
}
|
|
while ((n = getline (&line, &len, fp)) != -1) {
|
|
CHOMP (line, n);
|
|
if (STRPREFIX (line, vendor)) {
|
|
/* Find the start of the name after the vendor ID and whitespace. */
|
|
size_t i = 4;
|
|
n -= 4;
|
|
|
|
while (n > 0 && isspace (line[i])) {
|
|
i++;
|
|
n--;
|
|
}
|
|
|
|
memmove (&line[0], &line[i], n+1 /* copy trailing \0 */);
|
|
|
|
/* Truncate? */
|
|
if (truncate > 0 && n > truncate)
|
|
line[n] = '\0';
|
|
|
|
return line;
|
|
}
|
|
}
|
|
|
|
free (line);
|
|
return NULL;
|
|
}
|
|
|
|
/* Wait for the network to come online, but don't error out if that
|
|
* fails. The caller will call test_connection immediately after this
|
|
* which will fail if the network didn't come online.
|
|
*/
|
|
|
|
/* XXX We could make this configurable. */
|
|
#define NETWORK_ONLINE_COMMAND "nm-online -t 30"
|
|
|
|
void
|
|
wait_network_online (const struct config *config)
|
|
{
|
|
if (config->verbose) {
|
|
printf ("waiting for the network to come online ...\n");
|
|
printf ("%s\n", NETWORK_ONLINE_COMMAND);
|
|
fflush (stdout);
|
|
}
|
|
|
|
ignore_value (system (NETWORK_ONLINE_COMMAND));
|
|
}
|