Intorduce new monitor functions to get the media status (ejected
or inserted) of removable block device via qemu monitor command
"info block".
QEMU upstream will expose the the media status like:
cd: type=cdrom removable=1 locked=0 ejected=0
The related patch:
http://lists.gnu.org/archive/html/qemu-devel/2011-08/msg00408.html
Although it's unlikely to expose other information of removable
block device in future via the new function, returned the info
in argument "*ejected" just in case of there is new requirement
to expose other info.
---
src/qemu/qemu_monitor.c | 20 ++++++++
src/qemu/qemu_monitor.h | 3 +
src/qemu/qemu_monitor_json.c | 14 ++++++
src/qemu/qemu_monitor_json.h | 4 +-
src/qemu/qemu_monitor_text.c | 105 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 3 +
6 files changed, 148 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db6107c..7a41e8f 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1227,6 +1227,26 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected)
+{
+ int ret;
+ VIR_DEBUG("mon=%p dev=%s", mon, devname);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONGetRemovableBlockMediaStatus(mon, devname, ejected);
+ else
+ ret = qemuMonitorTextGetRemovableBlockMediaStatus(mon, devname, ejected);
+ return ret;
+}
+
int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
const char *devname,
unsigned long long *extent)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f241c9e..e533cbd 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -215,6 +215,9 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
long long *wr_req,
long long *wr_bytes,
long long *errs);
+int qemuMonitorGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected);
int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
const char *devname,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2a9a078..f59489d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1519,6 +1519,20 @@ cleanup:
return ret;
}
+int qemuMonitorJSONGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected)
+{
+ /* XXX: No QMP command like "info block" which can get the
+ * block device information yet.
+ */
+ if (qemuMonitorCheckHMP(mon, "info block")) {
+ return qemuMonitorTextGetRemovableBlockMediaStatus(mon, devname,
+ ejected);
+ } else {
+ return -1;
+ }
+}
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
const char *password)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 9512793..33158c9 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -70,7 +70,9 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
const char *devname,
unsigned long long *extent);
-
+int qemuMonitorJSONGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected);
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
const char *password);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 7bf733d..02ed82f 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -786,6 +786,111 @@ int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon
ATTRIBUTE_UNUSED,
return -1;
}
+/* Get the media status (ejected or inserted) of removable block
+ * device.
+ *
+ * Return -1 on failure, 0 on success.
+ */
+int qemuMonitorTextGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected)
+{
+ int ret = -1;
+ char *info = NULL;
+ char *dummy;
+ const char *p, *eol;
+ int devnamelen = strlen(devname);
+
+ if (qemuMonitorHMPCommand (mon, "info block", &info) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("'info block' command
failed"));
+ goto cleanup;
+ }
+
+ /* If the command isn't supported then qemu prints the supported
+ * info commands, so the output starts "info ". Since this is
+ * unlikely to be the name of a block device, we can use this
+ * to detect if qemu supports the command.
+ */
+ if (strstr(info, "\ninfo ")) {
+ qemuReportError(VIR_ERR_NO_SUPPORT,
+ "%s",
+ _("'info block' not supported by this qemu"));
+ goto cleanup;
+ }
+
+ /* The output format of "info block" is like:
+ * disk: type=hd removable=0 file=/var/lib/libvirt/images/test.img ro=0 \
+ * drv=raw encrypted=0
+ * cd: type=cdrom removable=1 locked=0 ejected=0 (without media inserted)
+ * (repeated for each block device)
+ */
+ p = info;
+
+ while (*p) {
+ /* New QEMU has separate names for host & guest side of the disk
+ * and libvirt gives the host side a 'drive-' prefix. The passed
+ * in devname is the guest side though
+ */
+ if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
+ p += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+ if (STREQLEN (p, devname, devnamelen)
+ && p[devnamelen] == ':' && p[devnamelen+1] == '
') {
+
+ eol = strchr (p, '\n');
+ if (!eol)
+ eol = p + strlen (p);
+
+ p += devnamelen + 2; /* Skip to first label. */
+
+ while (*p) {
+ VIR_WARN("p = %s", p);
+
+ /* Make sure the device is removable, we don't want to waste
+ * time on querying a not removable device.
+ */
+ if (!strstr(p, "ejected=")) {
+ qemuReportError (VIR_ERR_OPERATION_INVALID,
+ _("device %s is not removable"),
devname);
+ return -1;
+ }
+
+ if (STRPREFIX (p, "ejected=")) {
+ p += strlen("ejected=");
+
+ if (virStrToLong_ui (p, &dummy, 10, ejected) == -1) {
+ qemuReportError (VIR_ERR_INTERNAL_ERROR,
+ _("error reading ejected: %s"), p);
+ return -1;
+ } else {
+ break;
+ }
+ }
+
+ /* Skip to next label. */
+ p = strchr (p, ' ');
+ if (!p || p >= eol) break;
+ p++;
+ }
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* Skip to next line. */
+ p = strchr (p, '\n');
+ if (!p) break;
+ p++;
+ }
+
+ /* If we reach here then the device was not found. */
+ qemuReportError (VIR_ERR_INVALID_ARG,
+ _("no stats found for device %s"), devname);
+
+ cleanup:
+ VIR_FREE(info);
+ return ret;
+}
static int
qemuMonitorSendVNCPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b250738..bfd1f7e 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -67,6 +67,9 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon,
const char *devname,
unsigned long long *extent);
+int qemuMonitorTextGetRemovableBlockMediaStatus(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned int *ejected);
int qemuMonitorTextSetVNCPassword(qemuMonitorPtr mon,
const char *password);
--
1.7.6