This patch adds a new flag to the 'create' and 'start' commands in virsh, making it immeditely spawn the builtin virsh console, eg # virsh start --console demo At the same time, I also add in a check for virConnectGetHostname() against the local hostname, and refuse to launch the console if they differ. With remote hypervisors it is obviously not possible to access the /dev/pts files directly. Without this check, the console may work by pure luck if there happens to be a matching device name on the local host. Rather confusing, and even potentially dangerous. # virsh -c qemu+ssh://root@xxxxxxxxxxxxxxxx/system console someguest error: Cannot connect to a remote console device Finally, when starting the console print a message telling the user the hotkey to quit # virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit Daniel diff -r a203154020dd src/virsh.c --- a/src/virsh.c Wed Apr 01 11:57:25 2009 +0100 +++ b/src/virsh.c Wed Apr 01 13:36:40 2009 +0100 @@ -500,20 +500,30 @@ static const vshCmdOptDef opts_console[] #ifndef __MINGW32__ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd) +cmdRunConsole(vshControl *ctl, virDomainPtr dom) { 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, NULL))) - return FALSE; + char *thatHost = NULL; + char *thisHost = NULL; + + if (!(thisHost = virGetHostname())) { + vshError(ctl, FALSE, "%s", _("Failed to get local hostname")); + goto cleanup; + } + + if (!(thatHost = virConnectGetHostname(ctl->conn))) { + vshError(ctl, FALSE, "%s", _("Failed to get connection hostname")); + goto cleanup; + } + + if (STRNEQ(thisHost, thatHost)) { + vshError(ctl, FALSE, "%s", _("Cannot connect to a remote console device")); + goto cleanup; + } doc = virDomainGetXMLDesc(dom, 0); if (!doc) @@ -532,6 +542,7 @@ cmdConsole(vshControl *ctl, const vshCmd obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); if ((obj != NULL) && ((obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0))) { + vshPrintExtra(ctl, "%s", _("Connecting to console, type Ctrl+] to quit\n")); if (vshRunConsole((const char *)obj->stringval) == 0) ret = TRUE; } else { @@ -543,14 +554,16 @@ cmdConsole(vshControl *ctl, const vshCmd xmlXPathFreeContext(ctxt); if (xml) xmlFreeDoc(xml); - virDomainFree(dom); + free(thisHost); + free(thatHost); + return ret; } #else /* __MINGW32__ */ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +cmdRunConsole(vshControl *ctl, virDomainPtr dom ATTRIBUTE_UNUSED) { vshError (ctl, FALSE, "%s", _("console not implemented on this platform")); return FALSE; @@ -558,6 +571,24 @@ cmdConsole(vshControl *ctl, const vshCmd #endif /* __MINGW32__ */ +static int +cmdConsole(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + ret = cmdRunConsole(ctl, dom); + + virDomainFree(dom); + return ret; +} + /* * "list" command */ @@ -882,6 +913,7 @@ static const vshCmdInfo info_create[] = static const vshCmdOptDef opts_create[] = { {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML domain description")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -893,6 +925,7 @@ cmdCreate(vshControl *ctl, const vshCmd int found; int ret = TRUE; char *buffer; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -910,6 +943,8 @@ cmdCreate(vshControl *ctl, const vshCmd if (dom != NULL) { vshPrint(ctl, _("Domain %s created from %s\n"), virDomainGetName(dom), from); + if (console) + cmdRunConsole(ctl, dom); virDomainFree(dom); } else { vshError(ctl, FALSE, _("Failed to create domain from %s"), from); @@ -1030,6 +1065,7 @@ static const vshCmdInfo info_start[] = { static const vshCmdOptDef opts_start[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -1038,6 +1074,7 @@ cmdStart(vshControl *ctl, const vshCmd * { virDomainPtr dom; int ret = TRUE; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -1054,6 +1091,8 @@ cmdStart(vshControl *ctl, const vshCmd * if (virDomainCreate(dom) == 0) { vshPrint(ctl, _("Domain %s started\n"), virDomainGetName(dom)); + if (console) + cmdRunConsole(ctl, dom); } else { vshError(ctl, FALSE, _("Failed to start domain %s"), virDomainGetName(dom)); -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list