mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
Flexible guestfs_vmchannel parameter for future appliances.
This reimplements parts of commit da0a4f8d1f
in a different, but compatible way.
We pass guestfs_vmchannel=tcp:<ip>:<port> on the command line. This
is intended to be used as follows (now and in future versions):
tcp:10.0.2.4:6666 for guestfwd vmchannel
tcp:10.0.2.2:<port> for future "no vmchannel" implementation
/dev/vcon4 for future virtio-console vmchannel*
It also accepts the old-style guestfs=10.0.2.4:6666 parameter which
is sent by older libraries, and turns this transparently into the
correct format above.
If no guestfs_vmchannel is passed, then this defaults to the guestfwd
vmchannel which older libraries would expect.
* Maybe this last one should be dev:/dev/vcon4 or file:/dev/vcon4, but
we don't need to decide that now.
This commit is contained in:
@@ -40,7 +40,6 @@
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
static void usage (void);
|
||||
static char *read_cmdline (void);
|
||||
|
||||
/* Also in guestfs.c */
|
||||
@@ -65,18 +64,28 @@ static int print_arginfo (const struct printf_info *info, size_t n, int *argtype
|
||||
const char *sysroot = "/sysroot"; /* No trailing slash. */
|
||||
int sysroot_len = 8;
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"guestfsd [-f|--foreground] [-c|--channel vmchannel] [-v|--verbose]\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
static const char *options = "f?";
|
||||
static const char *options = "fc:v?";
|
||||
static const struct option long_options[] = {
|
||||
{ "channel", required_argument, 0, 'c' },
|
||||
{ "foreground", 0, 0, 'f' },
|
||||
{ "help", 0, 0, '?' },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
int c;
|
||||
int dont_fork = 0;
|
||||
char *cmdline;
|
||||
char *vmchannel = NULL;
|
||||
|
||||
#ifdef HAVE_REGISTER_PRINTF_SPECIFIER
|
||||
/* http://udrepper.livejournal.com/20948.html */
|
||||
@@ -96,10 +105,18 @@ main (int argc, char *argv[])
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 'c':
|
||||
vmchannel = optarg;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
dont_fork = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage ();
|
||||
exit (0);
|
||||
@@ -118,7 +135,8 @@ main (int argc, char *argv[])
|
||||
cmdline = read_cmdline ();
|
||||
|
||||
/* Set the verbose flag. */
|
||||
verbose = cmdline && strstr (cmdline, "guestfs_verbose=1") != NULL;
|
||||
verbose = verbose ||
|
||||
(cmdline && strstr (cmdline, "guestfs_verbose=1") != NULL);
|
||||
if (verbose)
|
||||
printf ("verbose daemon enabled\n");
|
||||
|
||||
@@ -148,38 +166,129 @@ main (int argc, char *argv[])
|
||||
/* We document that umask defaults to 022 (it should be this anyway). */
|
||||
umask (022);
|
||||
|
||||
/* Resolve the hostname. */
|
||||
struct addrinfo *res, *rr;
|
||||
struct addrinfo hints;
|
||||
int r;
|
||||
memset (&hints, 0, sizeof hints);
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
r = getaddrinfo (GUESTFWD_ADDR, GUESTFWD_PORT, &hints, &res);
|
||||
if (r != 0) {
|
||||
fprintf (stderr, "%s:%s: %s\n",
|
||||
GUESTFWD_ADDR, GUESTFWD_PORT, gai_strerror (r));
|
||||
/* Get the vmchannel string.
|
||||
*
|
||||
* Sources:
|
||||
* --channel/-c option on the command line
|
||||
* guestfs_vmchannel=... from the kernel command line
|
||||
* guestfs=... from the kernel command line
|
||||
* built-in default
|
||||
*
|
||||
* At the moment we expect this to contain "tcp:ip:port" but in
|
||||
* future it might contain a device name, eg. "/dev/vcon4" for
|
||||
* virtio-console vmchannel.
|
||||
*/
|
||||
if (vmchannel == NULL && cmdline) {
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
p = strstr (cmdline, "guestfs_vmchannel=");
|
||||
if (p) {
|
||||
len = strcspn (p + 18, " \t\n");
|
||||
vmchannel = strndup (p + 18, len);
|
||||
if (!vmchannel) {
|
||||
perror ("strndup");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Old libraries passed guestfs=host:port. Rewrite it as tcp:host:port. */
|
||||
if (vmchannel == NULL) {
|
||||
/* We will rewrite it part of the "guestfs=" string with
|
||||
* "tcp:" hence p + 4 below. */
|
||||
p = strstr (cmdline, "guestfs=");
|
||||
if (p) {
|
||||
len = strcspn (p + 4, " \t\n");
|
||||
vmchannel = strndup (p + 4, len);
|
||||
if (!vmchannel) {
|
||||
perror ("strndup");
|
||||
exit (1);
|
||||
}
|
||||
memcpy (vmchannel, "tcp:", 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Default vmchannel. */
|
||||
if (vmchannel == NULL) {
|
||||
vmchannel = strdup ("tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT);
|
||||
if (!vmchannel) {
|
||||
perror ("strdup");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf ("vmchannel: %s\n", vmchannel);
|
||||
|
||||
/* Connect to vmchannel. */
|
||||
int sock = -1;
|
||||
|
||||
if (strncmp (vmchannel, "tcp:", 4) == 0) {
|
||||
/* Resolve the hostname. */
|
||||
struct addrinfo *res, *rr;
|
||||
struct addrinfo hints;
|
||||
int r;
|
||||
char *host, *port;
|
||||
|
||||
host = vmchannel+4;
|
||||
port = strchr (host, ':');
|
||||
if (port) {
|
||||
port[0] = '\0';
|
||||
port++;
|
||||
} else {
|
||||
fprintf (stderr, "vmchannel: expecting \"tcp:<ip>:<port>\": %s\n",
|
||||
vmchannel);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
memset (&hints, 0, sizeof hints);
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
r = getaddrinfo (host, port, &hints, &res);
|
||||
if (r != 0) {
|
||||
fprintf (stderr, "%s:%s: %s\n",
|
||||
host, port, gai_strerror (r));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Connect to the given TCP socket. */
|
||||
for (rr = res; rr != NULL; rr = rr->ai_next) {
|
||||
sock = socket (rr->ai_family, rr->ai_socktype, rr->ai_protocol);
|
||||
if (sock != -1) {
|
||||
if (connect (sock, rr->ai_addr, rr->ai_addrlen) == 0)
|
||||
break;
|
||||
perror ("connect");
|
||||
|
||||
close (sock);
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
freeaddrinfo (res);
|
||||
} else {
|
||||
fprintf (stderr,
|
||||
"unknown vmchannel connection type: %s\n"
|
||||
"expecting \"tcp:<ip>:<port>\"\n",
|
||||
vmchannel);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Connect to the given TCP socket. */
|
||||
int sock = -1;
|
||||
for (rr = res; rr != NULL; rr = rr->ai_next) {
|
||||
sock = socket (rr->ai_family, rr->ai_socktype, rr->ai_protocol);
|
||||
if (sock != -1) {
|
||||
if (connect (sock, rr->ai_addr, rr->ai_addrlen) == 0)
|
||||
break;
|
||||
perror ("connect");
|
||||
|
||||
close (sock);
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
freeaddrinfo (res);
|
||||
|
||||
if (sock == -1) {
|
||||
fprintf (stderr, "connection to %s:%s failed\n",
|
||||
GUESTFWD_ADDR, GUESTFWD_PORT);
|
||||
fprintf (stderr,
|
||||
"\n"
|
||||
"Failed to connect to any vmchannel implementation.\n"
|
||||
"vmchannel: %s\n"
|
||||
"\n"
|
||||
"This is a fatal error and the appliance will now exit.\n"
|
||||
"\n"
|
||||
"Usually this error is caused by either QEMU or the appliance\n"
|
||||
"kernel not supporting the vmchannel method that the\n"
|
||||
"libguestfs library chose to use. Please run\n"
|
||||
"'libguestfs-test-tool' and provide the complete, unedited\n"
|
||||
"output to the libguestfs developers, either in a bug report\n"
|
||||
"or on the libguestfs redhat com mailing list.\n"
|
||||
"\n",
|
||||
vmchannel);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -323,12 +432,6 @@ xread (int sock, void *v_buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr, "guestfsd [-f]\n");
|
||||
}
|
||||
|
||||
int
|
||||
add_string (char ***argv, int *size, int *alloc, const char *str)
|
||||
{
|
||||
|
||||
@@ -984,6 +984,7 @@ guestfs__launch (guestfs_h *g)
|
||||
|
||||
if (r == 0) { /* Child (qemu). */
|
||||
char buf[256];
|
||||
const char *vmchannel = NULL;
|
||||
|
||||
/* Set up the full command line. Do this in the subprocess so we
|
||||
* don't need to worry about cleaning up.
|
||||
@@ -1045,6 +1046,7 @@ guestfs__launch (guestfs_h *g)
|
||||
}
|
||||
add_cmdline (g, "-net");
|
||||
add_cmdline (g, "nic,model=" NET_IF ",vlan=0");
|
||||
vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT " ";
|
||||
|
||||
#define LINUX_CMDLINE \
|
||||
"panic=1 " /* force kernel to panic if daemon exits */ \
|
||||
@@ -1058,9 +1060,11 @@ guestfs__launch (guestfs_h *g)
|
||||
snprintf (buf, sizeof buf,
|
||||
LINUX_CMDLINE
|
||||
"%s" /* (selinux) */
|
||||
"%s" /* (vmchannel) */
|
||||
"%s" /* (verbose) */
|
||||
"%s", /* (append) */
|
||||
g->selinux ? "selinux=1 enforcing=0 " : "selinux=0 ",
|
||||
vmchannel ? vmchannel : "",
|
||||
g->verbose ? "guestfs_verbose=1 " : "",
|
||||
g->append ? g->append : "");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user