qemu: chardev: Extract more information about character devices

Improve the monitor function to also retrieve the guest state of
character device (if provided) so that we can refresh the state of
virtio-serial channels and perhaps react to changes in the state in
future patches.

This patch changes the returned data from qemuMonitorGetChardevInfo to
return a structure containing the pty path and the state for all the
character devices.

The change to the testsuite makes sure that the data is parsed
correctly.
This commit is contained in:
Peter Krempa 2014-11-13 19:29:14 +01:00
parent 42874fa45f
commit 4d7eb90311
6 changed files with 106 additions and 36 deletions

View File

@ -2982,6 +2982,17 @@ qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
}
static void
qemuMonitorChardevInfoFree(void *data,
const void *name ATTRIBUTE_UNUSED)
{
qemuMonitorChardevInfoPtr info = data;
VIR_FREE(info->ptyPath);
VIR_FREE(info);
}
int
qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
virHashTablePtr *retinfo)
@ -2997,7 +3008,7 @@ qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
goto error;
}
if (!(info = virHashCreate(10, virHashValueFree)))
if (!(info = virHashCreate(10, qemuMonitorChardevInfoFree)))
goto error;
if (mon->json)

View File

@ -649,6 +649,12 @@ int qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
int qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
virNetDevRxFilterPtr *filter);
typedef struct _qemuMonitorChardevInfo qemuMonitorChardevInfo;
typedef qemuMonitorChardevInfo *qemuMonitorChardevInfoPtr;
struct _qemuMonitorChardevInfo {
char *ptyPath;
virDomainChrDeviceState state;
};
int qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
virHashTablePtr *retinfo);

View File

@ -3414,7 +3414,7 @@ qemuMonitorJSONQueryRxFilter(qemuMonitorPtr mon, const char *alias,
*
* {"return": [
* {"filename": "stdio", "label": "monitor"},
* {"filename": "pty:/dev/pts/6", "label": "serial0"},
* {"filename": "pty:/dev/pts/6", "label": "serial0", "frontend-open": true},
* {"filename": "pty:/dev/pts/7", "label": "parallel0"}
* ]}
*
@ -3426,6 +3426,7 @@ qemuMonitorJSONExtractChardevInfo(virJSONValuePtr reply,
virJSONValuePtr data;
int ret = -1;
size_t i;
qemuMonitorChardevInfoPtr entry = NULL;
if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -3440,44 +3441,60 @@ qemuMonitorJSONExtractChardevInfo(virJSONValuePtr reply,
}
for (i = 0; i < virJSONValueArraySize(data); i++) {
virJSONValuePtr entry = virJSONValueArrayGet(data, i);
virJSONValuePtr chardev = virJSONValueArrayGet(data, i);
const char *type;
const char *id;
if (!entry) {
const char *alias;
bool connected;
if (!chardev) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("character device information was missing array element"));
goto cleanup;
}
if (!(type = virJSONValueObjectGetString(entry, "filename"))) {
if (!(alias = virJSONValueObjectGetString(chardev, "label"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("character device information was missing label"));
goto cleanup;
}
if (!(type = virJSONValueObjectGetString(chardev, "filename"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("character device information was missing filename"));
goto cleanup;
}
if (!(id = virJSONValueObjectGetString(entry, "label"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("character device information was missing filename"));
if (VIR_ALLOC(entry) < 0)
goto cleanup;
if (STRPREFIX(type, "pty:") &&
VIR_STRDUP(entry->ptyPath, type + strlen("pty:")) < 0)
goto cleanup;
if (virJSONValueObjectGetBoolean(chardev, "frontend-open", &connected) == 0) {
if (connected)
entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
else
entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
}
if (virHashAddEntry(info, alias, entry) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("failed to add chardev '%s' info"), alias);
goto cleanup;
}
if (STRPREFIX(type, "pty:")) {
char *path;
if (VIR_STRDUP(path, type + strlen("pty:")) < 0)
goto cleanup;
if (virHashAddEntry(info, id, path) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("failed to save chardev path '%s'"), path);
VIR_FREE(path);
goto cleanup;
}
}
entry = NULL;
}
ret = 0;
cleanup:
if (entry) {
VIR_FREE(entry->ptyPath);
VIR_FREE(entry);
}
return ret;
}

View File

@ -2174,6 +2174,7 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
virHashTablePtr info)
{
char *reply = NULL;
qemuMonitorChardevInfoPtr entry = NULL;
int ret = -1;
if (qemuMonitorHMPCommand(mon, "info chardev", &reply) < 0)
@ -2218,17 +2219,22 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
/* Path is everything after needle to the end of the line */
*eol = '\0';
char *path;
if (VIR_STRDUP(path, needle + strlen(NEEDLE)) < 0)
if (VIR_ALLOC(entry) < 0)
goto cleanup;
if (virHashAddEntry(info, id, path) < 0) {
if (VIR_STRDUP(entry->ptyPath, needle + strlen(NEEDLE)) < 0)
goto cleanup;
if (virHashAddEntry(info, id, entry) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("failed to save chardev path '%s'"),
path);
VIR_FREE(path);
entry->ptyPath);
VIR_FREE(entry->ptyPath);
goto cleanup;
}
entry = NULL;
#undef NEEDLE
}
@ -2236,6 +2242,7 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
cleanup:
VIR_FREE(reply);
VIR_FREE(entry);
return ret;
}

View File

@ -1919,7 +1919,7 @@ qemuProcessLookupPTYs(virDomainDefPtr def,
if (chr->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
char id[32];
const char *path;
qemuMonitorChardevInfoPtr entry;
if (snprintf(id, sizeof(id), "%s%s",
chardevfmt ? "char" : "",
@ -1930,8 +1930,8 @@ qemuProcessLookupPTYs(virDomainDefPtr def,
return -1;
}
path = (const char *) virHashLookup(info, id);
if (path == NULL) {
entry = virHashLookup(info, id);
if (!entry || !entry->ptyPath) {
if (chr->source.data.file.path == NULL) {
/* neither the log output nor 'info chardev' had a
* pty path for this chardev, report an error
@ -1948,7 +1948,7 @@ qemuProcessLookupPTYs(virDomainDefPtr def,
}
VIR_FREE(chr->source.data.file.path);
if (VIR_STRDUP(chr->source.data.file.path, path) < 0)
if (VIR_STRDUP(chr->source.data.file.path, entry->ptyPath) < 0)
return -1;
}
}

View File

@ -1759,11 +1759,28 @@ testQemuMonitorJSONqemuMonitorJSONGetSpiceMigrationStatus(const void *data)
}
static int
testHashEqualString(const void *value1, const void *value2)
testHashEqualChardevInfo(const void *value1, const void *value2)
{
return strcmp(value1, value2);
const qemuMonitorChardevInfo *info1 = value1;
const qemuMonitorChardevInfo *info2 = value2;
if (info1->state != info2->state)
goto error;
if (STRNEQ_NULLABLE(info1->ptyPath, info2->ptyPath))
goto error;
return 0;
error:
fprintf(stderr, "\n"
"info1->state: %d info2->state: %d\n"
"info1->ptyPath: %s info2->ptyPath: %s\n",
info1->state, info2->state, info1->ptyPath, info2->ptyPath);
return -1;
}
static int
testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
{
@ -1771,6 +1788,10 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
int ret = -1;
virHashTablePtr info = NULL, expectedInfo = NULL;
qemuMonitorChardevInfo info0 = { NULL, VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT };
qemuMonitorChardevInfo info1 = { (char *) "/dev/pts/21", VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED };
qemuMonitorChardevInfo info2 = { (char *) "/dev/pts/20", VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT };
qemuMonitorChardevInfo info3 = { NULL, VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED };
if (!test)
return -1;
@ -1779,8 +1800,10 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
!(expectedInfo = virHashCreate(32, NULL)))
goto cleanup;
if (virHashAddEntry(expectedInfo, "charserial1", (void *) "/dev/pts/21") < 0 ||
virHashAddEntry(expectedInfo, "charserial0", (void *) "/dev/pts/20") < 0) {
if (virHashAddEntry(expectedInfo, "charserial1", &info1) < 0 ||
virHashAddEntry(expectedInfo, "charserial0", &info2) < 0 ||
virHashAddEntry(expectedInfo, "charmonitor", &info0) < 0 ||
virHashAddEntry(expectedInfo, "charserial2", &info3) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"Unable to create expectedInfo hash table");
goto cleanup;
@ -1791,7 +1814,8 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
" \"return\": ["
" {"
" \"filename\": \"pty:/dev/pts/21\","
" \"label\": \"charserial1\""
" \"label\": \"charserial1\","
" \"frontend-open\": true"
" },"
" {"
" \"filename\": \"pty:/dev/pts/20\","
@ -1800,6 +1824,11 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
" {"
" \"filename\": \"unix:/var/lib/libvirt/qemu/gentoo.monitor,server\","
" \"label\": \"charmonitor\""
" },"
" {"
" \"filename\": \"unix:/path/to/socket,server\","
" \"label\": \"charserial2\","
" \"frontend-open\": false"
" }"
" ],"
" \"id\": \"libvirt-15\""
@ -1810,7 +1839,7 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
info) < 0)
goto cleanup;
if (!virHashEqual(info, expectedInfo, testHashEqualString)) {
if (!virHashEqual(info, expectedInfo, testHashEqualChardevInfo)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"Hashtable is different to the expected one");
goto cleanup;