return 1;
}
+static int
+qemudFindCharDevicePTYsMonitor(virConnectPtr conn,
+ virDomainObjPtr vm,
+ virHashTablePtr paths)
+{
+ int i;
+
+#define LOOKUP_PTYS(array, arraylen, idprefix) \
+ for (i = 0 ; i < (arraylen) ; i++) { \
+ virDomainChrDefPtr chr = (array)[i]; \
+ if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { \
+ char id[16]; \
+ \
+ if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \
+ return -1; \
+ \
+ const char *path = (const char *) virHashLookup(paths, id); \
+ if (path == NULL) { \
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,\
+ _("no assigned pty for device %s"), id); \
+ return -1; \
+ } \
+ \
+ chr->data.file.path = strdup(path); \
+ } \
+ }
+
+ LOOKUP_PTYS(vm->def->serials, vm->def->nserials, "serial");
+ LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel");
+ LOOKUP_PTYS(vm->def->channels, vm->def->nchannels, "channel");
+
+ return 0;
+}
+
static int
qemudFindCharDevicePTYs(virConnectPtr conn,
virDomainObjPtr vm,
return 0;
}
+static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+ VIR_FREE(payload);
+}
+
static int
qemudWaitForMonitor(virConnectPtr conn,
struct qemud_driver* driver,
{
char buf[4096]; /* Plenty of space to get startup greeting */
int logfd;
- int ret;
+ int ret = -1;
if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos))
< 0)
if (qemuConnectMonitor(vm) < 0)
return -1;
- return 0;
+ /* Try to get the pty path mappings again via the monitor. This is much more
+ * reliable if it's available.
+ * Note that the monitor itself can be on a pty, so we still need to try the
+ * log output method. */
+ virHashTablePtr paths = virHashCreate(0);
+ if (paths == NULL) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ ret = qemuMonitorGetPtyPaths(priv->mon, paths);
+ qemuDomainObjExitMonitor(vm);
+
+ VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
+ if (ret == 0) {
+ ret = qemudFindCharDevicePTYsMonitor(conn, vm, paths);
+ }
+
+cleanup:
+ if (paths) {
+ virHashFree(paths, qemudFreePtyPath);
+ }
+
+ return ret;
}
static int
ret = qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
return ret;
}
+
+int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
+ virHashTablePtr paths)
+{
+ DEBUG("mon=%p, fd=%d",
+ mon, mon->fd);
+
+ return qemuMonitorTextGetPtyPaths(mon, paths);
+}
#include "internal.h"
#include "domain_conf.h"
+#include "hash.h"
typedef struct _qemuMonitor qemuMonitor;
typedef qemuMonitor *qemuMonitorPtr;
int vlan,
const char *netname);
+int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
+ virHashTablePtr paths);
#endif /* QEMU_MONITOR_H */
VIR_FREE(reply);
return ret;
}
+
+
+/* Parse the output of "info chardev" and return a hash of pty paths.
+ *
+ * Output is:
+ * foo: filename=pty:/dev/pts/7
+ * monitor: filename=stdio
+ * serial0: filename=vc
+ * parallel0: filename=vc
+ *
+ * Non-pty lines are ignored. In the above example, key is 'foo', value is
+ * '/dev/pty/7'. The hash will contain only a single value.
+ */
+
+int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
+ virHashTablePtr paths)
+{
+ const char *cmd = "info chardev";
+ char *reply = NULL;
+ int ret = -1;
+
+ if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("failed to retrieve chardev info in qemu with '%s'"),
+ cmd);
+ goto cleanup;
+ }
+
+ char *pos = reply; /* The current start of searching */
+ char *end = pos + strlen(reply); /* The end of the reply string */
+ char *eol; /* The character which ends the current line */
+
+ while (pos < end) {
+ /* Split the output into lines */
+ eol = memchr(pos, '\n', end - pos);
+ if (eol == NULL)
+ eol = end;
+
+ /* Look for 'filename=pty:' */
+#define NEEDLE "filename=pty:"
+ char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE));
+
+ /* If it's not there we can ignore this line */
+ if (!needle)
+ goto next;
+
+ /* id is everthing from the beginning of the line to the ':'
+ * find ':' and turn it into a terminator */
+ char *colon = memchr(pos, ':', needle - pos);
+ if (colon == NULL)
+ goto next;
+ *colon = '\0';
+ char *id = pos;
+
+ /* Path is everything after needle to the end of the line */
+ *eol = '\0';
+ char *path = needle + strlen(NEEDLE);
+
+ virHashAddEntry(paths, id, strdup(path));
+#undef NEEDLE
+
+ next:
+ pos = eol + 1;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(reply);
+ return ret;
+}
#include "internal.h"
#include "qemu_monitor.h"
+#include "hash.h"
int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
const char *data,
int vlan,
const char *netname);
+int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
+ virHashTablePtr paths);
+
#endif /* QEMU_MONITOR_TEXT_H */