mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-12 16:35:58 -06:00
Added vncdisplay & console commands to virsh
This commit is contained in:
parent
079dc77af6
commit
786024b7dd
@ -1,3 +1,10 @@
|
||||
Fri Jan 26 06:53:52 EST 2007 Daniel Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virshc: Added 'console' and 'vncdisplay' commands to
|
||||
the virsh tool
|
||||
* src/console.c, src/console.h: Impl of a simple interactive
|
||||
serial console
|
||||
|
||||
Fri Jan 26 12:48:13 CET 2007 Daniel Veillard <veillard@redhat.com>
|
||||
|
||||
* src/virsh.c: Richard W.M. Jones pointed out a missing option
|
||||
|
@ -32,7 +32,7 @@ libvirt_la_SOURCES = \
|
||||
|
||||
bin_PROGRAMS = virsh
|
||||
|
||||
virsh_SOURCES = virsh.c
|
||||
virsh_SOURCES = virsh.c console.c console.h
|
||||
virsh_LDFLAGS =
|
||||
virsh_DEPENDENCIES = $(DEPS)
|
||||
virsh_LDADD = $(LDADDS) $(VIRSH_LIBS)
|
||||
|
188
src/console.c
Normal file
188
src/console.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* console.c: A dumb serial console client
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Daniel Berrange <berrange@redhat.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* ie Ctrl-] as per telnet */
|
||||
#define CTRL_CLOSE_BRACKET '\35'
|
||||
|
||||
static int got_signal = 0;
|
||||
static void do_signal(int sig ATTRIBUTE_UNUSED) {
|
||||
got_signal = 1;
|
||||
}
|
||||
|
||||
int virRunConsole(const char *tty) {
|
||||
int ttyfd, ret = -1;
|
||||
struct termios ttyattr, rawattr;
|
||||
void (*old_sigquit)(int);
|
||||
void (*old_sigterm)(int);
|
||||
void (*old_sigint)(int);
|
||||
void (*old_sighup)(int);
|
||||
void (*old_sigpipe)(int);
|
||||
|
||||
|
||||
/* We do not want this to become the controlling TTY */
|
||||
if ((ttyfd = open(tty, O_NOCTTY | O_RDWR)) < 0) {
|
||||
fprintf(stderr, _("unable to open tty %s: %s\n"),
|
||||
tty, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put STDIN into raw mode so that stuff typed
|
||||
does not echo to the screen (the TTY reads will
|
||||
result in it being echoed back already), and
|
||||
also ensure Ctrl-C, etc is blocked, and misc
|
||||
other bits */
|
||||
if (tcgetattr(STDIN_FILENO, &ttyattr) < 0) {
|
||||
fprintf(stderr, _("unable to get tty attributes: %s\n"),
|
||||
strerror(errno));
|
||||
goto closetty;
|
||||
}
|
||||
|
||||
rawattr = ttyattr;
|
||||
cfmakeraw(&rawattr);
|
||||
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) {
|
||||
fprintf(stderr, _("unable to set tty attributes: %s\n"),
|
||||
strerror(errno));
|
||||
goto closetty;
|
||||
}
|
||||
|
||||
|
||||
/* Trap all common signals so that we can safely restore
|
||||
the original terminal settings on STDIN before the
|
||||
process exits - people don't like being left with a
|
||||
messed up terminal ! */
|
||||
old_sigquit = signal(SIGQUIT, do_signal);
|
||||
old_sigterm = signal(SIGTERM, do_signal);
|
||||
old_sigint = signal(SIGINT, do_signal);
|
||||
old_sighup = signal(SIGHUP, do_signal);
|
||||
old_sigpipe = signal(SIGPIPE, do_signal);
|
||||
got_signal = 0;
|
||||
|
||||
|
||||
/* Now lets process STDIN & tty forever.... */
|
||||
for (; !got_signal ;) {
|
||||
unsigned int i;
|
||||
struct pollfd fds[] = {
|
||||
{ STDIN_FILENO, POLLIN, 0 },
|
||||
{ ttyfd, POLLIN, 0 },
|
||||
};
|
||||
|
||||
/* Wait for data to be available for reading on
|
||||
STDIN or the tty */
|
||||
if (poll(fds, (sizeof(fds)/sizeof(struct pollfd)), -1) < 0) {
|
||||
if (got_signal)
|
||||
goto cleanup;
|
||||
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
fprintf(stderr, _("failure waiting for I/O: %s\n"),
|
||||
strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < (sizeof(fds)/sizeof(struct pollfd)) ; i++) {
|
||||
if (!fds[i].revents)
|
||||
continue;
|
||||
|
||||
/* Process incoming data available for read */
|
||||
if (fds[i].revents & POLLIN) {
|
||||
char buf[4096];
|
||||
int got, sent = 0, destfd;
|
||||
|
||||
if ((got = read(fds[i].fd, buf, sizeof(buf))) < 0) {
|
||||
fprintf(stderr, _("failure reading input: %s\n"),
|
||||
strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Quit if end of file, or we got the Ctrl-] key */
|
||||
if (!got ||
|
||||
(got == 1 &&
|
||||
buf[0] == CTRL_CLOSE_BRACKET))
|
||||
goto done;
|
||||
|
||||
/* Data from stdin goes to the TTY,
|
||||
data from the TTY goes to STDOUT */
|
||||
if (fds[i].fd == STDIN_FILENO)
|
||||
destfd = ttyfd;
|
||||
else
|
||||
destfd = STDOUT_FILENO;
|
||||
|
||||
while (sent < got) {
|
||||
int done;
|
||||
if ((done = write(destfd, buf + sent, got - sent)) <= 0) {
|
||||
fprintf(stderr, _("failure writing output: %s\n"),
|
||||
strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
sent += done;
|
||||
}
|
||||
} else { /* Any other flag from poll is an error condition */
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Restore original signal handlers */
|
||||
signal(SIGQUIT, old_sigpipe);
|
||||
signal(SIGQUIT, old_sighup);
|
||||
signal(SIGQUIT, old_sigint);
|
||||
signal(SIGQUIT, old_sigterm);
|
||||
signal(SIGQUIT, old_sigquit);
|
||||
|
||||
/* Put STDIN back into the (sane?) state we found
|
||||
it in before starting */
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr);
|
||||
|
||||
closetty:
|
||||
close(ttyfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* indent-tabs-mode: nil
|
||||
* c-indent-level: 4
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
*/
|
45
src/console.h
Normal file
45
src/console.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* console.c: A dumb serial console client
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Daniel Berrange <berrange@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __VIR_CONSOLE_H__
|
||||
#define __VIR_CONSOLE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int virRunConsole(const char *tty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __VIR_CONSOLE_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* indent-tabs-mode: nil
|
||||
* c-indent-level: 4
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
*/
|
156
src/virsh.c
156
src/virsh.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* virsh.c: a Xen shell used to exercise the libvir API
|
||||
* virsh.c: a Xen shell used to exercise the libvirt API
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc.
|
||||
*
|
||||
@ -29,11 +29,16 @@
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "internal.h"
|
||||
#include "console.h"
|
||||
|
||||
static char *progname;
|
||||
|
||||
@ -305,6 +310,71 @@ cmdConnect(vshControl * ctl, vshCmd * cmd)
|
||||
return ctl->conn ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* "console" command
|
||||
*/
|
||||
static vshCmdInfo info_console[] = {
|
||||
{"syntax", "console <domain>"},
|
||||
{"help", gettext_noop("connect to the guest console")},
|
||||
{"desc",
|
||||
gettext_noop("Connect the virtual serial console for the guest")},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static vshCmdOptDef opts_console[] = {
|
||||
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
|
||||
{NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static int
|
||||
cmdConsole(vshControl * ctl, vshCmd * cmd)
|
||||
{
|
||||
xmlDocPtr xml = NULL;
|
||||
xmlXPathObjectPtr obj = NULL;
|
||||
xmlXPathContextPtr ctxt = NULL;
|
||||
virDomainPtr dom;
|
||||
int ret = FALSE;
|
||||
char *doc;
|
||||
|
||||
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
|
||||
return FALSE;
|
||||
|
||||
if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
|
||||
return FALSE;
|
||||
|
||||
doc = virDomainGetXMLDesc(dom, 0);
|
||||
if (!doc)
|
||||
goto cleanup;
|
||||
|
||||
xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
|
||||
XML_PARSE_NOENT | XML_PARSE_NONET |
|
||||
XML_PARSE_NOWARNING);
|
||||
free(doc);
|
||||
if (!xml)
|
||||
goto cleanup;
|
||||
ctxt = xmlXPathNewContext(xml);
|
||||
if (!ctxt)
|
||||
goto cleanup;
|
||||
|
||||
obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
|
||||
if ((obj != NULL) && ((obj->type == XPATH_STRING) &&
|
||||
(obj->stringval != NULL) && (obj->stringval[0] != 0))) {
|
||||
if (virRunConsole((const char *)obj->stringval) == 0)
|
||||
ret = TRUE;
|
||||
} else {
|
||||
vshPrintExtra(ctl, _("No console available for domain\n"));
|
||||
}
|
||||
xmlXPathFreeObject(obj);
|
||||
|
||||
cleanup:
|
||||
if (ctxt)
|
||||
xmlXPathFreeContext(ctxt);
|
||||
if (xml)
|
||||
xmlFreeDoc(xml);
|
||||
virDomainFree(dom);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* "list" command
|
||||
*/
|
||||
@ -1632,6 +1702,88 @@ cmdVersion(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* "dumpxml" command
|
||||
*/
|
||||
static vshCmdInfo info_vncdisplay[] = {
|
||||
{"syntax", "vncdisplay <domain>"},
|
||||
{"help", gettext_noop("vnc display")},
|
||||
{"desc", gettext_noop("Ouput the IP address and port number for the VNC display.")},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static vshCmdOptDef opts_vncdisplay[] = {
|
||||
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
|
||||
{NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static int
|
||||
cmdVNCDisplay(vshControl * ctl, vshCmd * cmd)
|
||||
{
|
||||
xmlDocPtr xml = NULL;
|
||||
xmlXPathObjectPtr obj = NULL;
|
||||
xmlXPathContextPtr ctxt = NULL;
|
||||
virDomainPtr dom;
|
||||
int ret = FALSE;
|
||||
int port = 0;
|
||||
char *doc;
|
||||
|
||||
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
|
||||
return FALSE;
|
||||
|
||||
if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
|
||||
return FALSE;
|
||||
|
||||
doc = virDomainGetXMLDesc(dom, 0);
|
||||
if (!doc)
|
||||
goto cleanup;
|
||||
|
||||
xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
|
||||
XML_PARSE_NOENT | XML_PARSE_NONET |
|
||||
XML_PARSE_NOWARNING);
|
||||
free(doc);
|
||||
if (!xml)
|
||||
goto cleanup;
|
||||
ctxt = xmlXPathNewContext(xml);
|
||||
if (!ctxt)
|
||||
goto cleanup;
|
||||
|
||||
obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@port)", ctxt);
|
||||
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
||||
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
||||
goto cleanup;
|
||||
}
|
||||
port = strtol((const char *)obj->stringval, NULL, 10);
|
||||
if (port == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
xmlXPathFreeObject(obj);
|
||||
|
||||
obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt);
|
||||
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
||||
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!strcmp((const char*)obj->stringval, "0.0.0.0")) {
|
||||
vshPrint(ctl, ":%d\n", port-5900);
|
||||
} else {
|
||||
vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
|
||||
}
|
||||
xmlXPathFreeObject(obj);
|
||||
obj = NULL;
|
||||
|
||||
cleanup:
|
||||
if (obj)
|
||||
xmlXPathFreeObject(obj);
|
||||
if (ctxt)
|
||||
xmlXPathFreeContext(ctxt);
|
||||
if (xml)
|
||||
xmlFreeDoc(xml);
|
||||
virDomainFree(dom);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "quit" command
|
||||
*/
|
||||
@ -1653,6 +1805,7 @@ cmdQuit(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
|
||||
*/
|
||||
static vshCmdDef commands[] = {
|
||||
{"connect", cmdConnect, opts_connect, info_connect},
|
||||
{"console", cmdConsole, opts_console, info_console},
|
||||
{"create", cmdCreate, opts_create, info_create},
|
||||
{"start", cmdStart, opts_start, info_start},
|
||||
{"destroy", cmdDestroy, opts_destroy, info_destroy},
|
||||
@ -1681,6 +1834,7 @@ static vshCmdDef commands[] = {
|
||||
{"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
|
||||
{"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
|
||||
{"version", cmdVersion, NULL, info_version},
|
||||
{"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user