mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-23 13:05:27 +00:00
Add APIs for issuing 'eject' and 'change dev' monitor commands
* 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.
This commit is contained in:
parent
eff29c8b28
commit
6d9c4758ae
@ -4572,9 +4572,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;
|
||||
@ -4620,53 +4620,19 @@ 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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user