* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new APis qemuMonitorChangeMedia and qemuMonitorEjectMedia. Pull in code for qemudEscape * src/qemu/qemu_driver.c: Remove code that directly issues 'eject' and 'change' commands in favour of API calls. --- src/qemu/qemu_driver.c | 52 +++----------- src/qemu/qemu_monitor_text.c | 159 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 10 +++ 3 files changed, 178 insertions(+), 43 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a0b5e49..b15dc03 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4573,9 +4573,9 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, unsigned int qemuCmdFlags) { virDomainDiskDefPtr origdisk = NULL, newdisk; - char *cmd, *reply, *safe_path; char *devname = NULL; int i; + int ret; origdisk = NULL; newdisk = dev->data.disk; @@ -4621,52 +4621,18 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, } if (newdisk->src) { - safe_path = qemudEscapeMonitorArg(newdisk->src); - if (!safe_path) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - if (virAsprintf(&cmd, "change %s \"%s\"", devname, safe_path) == -1) { - virReportOOMError(conn); - VIR_FREE(safe_path); - VIR_FREE(devname); - return -1; - } - VIR_FREE(safe_path); - - } else if (virAsprintf(&cmd, "eject %s", devname) == -1) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - VIR_FREE(devname); - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not change cdrom media")); - VIR_FREE(cmd); - return -1; + ret = qemuMonitorChangeMedia(vm, devname, newdisk->src); + } else { + ret = qemuMonitorEjectMedia(vm, devname); } - /* If the command failed qemu prints: - * device not found, device is locked ... - * No message is printed on success it seems */ - DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); - if (strstr(reply, "\ndevice ")) { - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("changing cdrom media failed: %s"), reply); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; + if (ret == 0) { + VIR_FREE(origdisk->src); + origdisk->src = newdisk->src; + newdisk->src = NULL; + origdisk->type = newdisk->type; } - VIR_FREE(reply); - VIR_FREE(cmd); - VIR_FREE(origdisk->src); - origdisk->src = newdisk->src; - newdisk->src = NULL; - origdisk->type = newdisk->type; return 0; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index be13dce..8be8047 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -40,6 +40,84 @@ #define VIR_FROM_THIS VIR_FROM_QEMU +static char *qemudEscape(const char *in, int shell) +{ + int len = 0; + int i, j; + char *out; + + /* To pass through the QEMU monitor, we need to use escape + sequences: \r, \n, \", \\ + + To pass through both QEMU + the shell, we need to escape + the single character ' as the five characters '\\'' + */ + + for (i = 0; in[i] != '\0'; i++) { + switch(in[i]) { + case '\r': + case '\n': + case '"': + case '\\': + len += 2; + break; + case '\'': + if (shell) + len += 5; + else + len += 1; + break; + default: + len += 1; + break; + } + } + + if (VIR_ALLOC_N(out, len + 1) < 0) + return NULL; + + for (i = j = 0; in[i] != '\0'; i++) { + switch(in[i]) { + case '\r': + out[j++] = '\\'; + out[j++] = 'r'; + break; + case '\n': + out[j++] = '\\'; + out[j++] = 'n'; + break; + case '"': + case '\\': + out[j++] = '\\'; + out[j++] = in[i]; + break; + case '\'': + if (shell) { + out[j++] = '\''; + out[j++] = '\\'; + out[j++] = '\\'; + out[j++] = '\''; + out[j++] = '\''; + } else { + out[j++] = in[i]; + } + break; + default: + out[j++] = in[i]; + break; + } + } + out[j] = '\0'; + + return out; +} + +static char *qemudEscapeMonitorArg(const char *in) +{ + return qemudEscape(in, 0); +} + + /* Throw away any data available on the monitor * This is done before executing a command, in order * to allow re-synchronization if something went badly @@ -651,3 +729,84 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, return ret; } +int qemuMonitorEjectMedia(const virDomainObjPtr vm, + const char *devname) +{ + char *cmd = NULL; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "eject %s", devname) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + + +int qemuMonitorChangeMedia(const virDomainObjPtr vm, + const char *devname, + const char *newmedia) +{ + char *cmd = NULL; + char *reply = NULL; + char *safepath = NULL; + int ret = -1; + + if (!(safepath = qemudEscapeMonitorArg(newmedia))) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&cmd, "change %s \"%s\"", devname, safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + VIR_FREE(safepath); + return ret; +} + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index e115791..d05dea1 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -81,4 +81,14 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, int qemuMonitorSetBalloon(const virDomainObjPtr vm, unsigned long newmem); +/* XXX should we pass the virDomainDiskDefPtr instead + * and hide devname details inside monitor. Reconsider + * this when doing the QMP implementation + */ +int qemuMonitorEjectMedia(const virDomainObjPtr vm, + const char *devname); +int qemuMonitorChangeMedia(const virDomainObjPtr vm, + const char *devname, + const char *newmedia); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list