For example:

./qemu-system -device virtio-blk,help

will raise the following error:

qemu-system: -device virtio-blk,help: Device alias 'virtio-blk' is ambiguous 
without a selected machine
Specify -machine <arch>-<machine-name> or an unambiguous <machine-name>, or use 
a concrete device name:
  virtio-blk-device
  virtio-blk-pci

Signed-off-by: Yonggang Luo <[email protected]>
---
 include/monitor/qdev.h |  7 ++++++
 system/qdev-monitor.c  | 52 ++++++++++++++++++++++++++++++++++++++----
 system/vl.c            |  7 +++---
 3 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index 8f7e2f616cf..92dd4e35351 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -10,6 +10,13 @@ void hmp_info_qtree(MonitorHMP *hmp, const QDict *qdict);
 void hmp_info_qdm(MonitorHMP *hmp, const QDict *qdict);
 void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
 
+/**
+ * qdev_device_help: print device listing or property help when requested.
+ * @opts: device options
+ *
+ * Returns: 0 if no help was requested, 1 if handled, or -1 if an ambiguous
+ * alias prevented help. Other property-help errors retain the handled result.
+ */
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
 DeviceState *qdev_device_add_from_qdict(const QDict *opts,
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index b3ca619f3c9..8ab19568b0d 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -24,6 +24,8 @@
 #include "monitor/monitor.h"
 #include "monitor/qdev.h"
 #include "qemu/base-arch-defs.h"
+#include "qemu/target-info.h"
+#include "qemu/target-info-def.h"
 #include "system/runstate.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-qdev.h"
@@ -217,10 +219,18 @@ static void qdev_print_devinfos(bool show_no_user)
     g_slist_free(list);
 }
 
-static const char *find_typename_by_alias(const char *alias)
+static const char *find_typename_by_alias(const char *alias, Error **errp)
 {
+    ERRP_GUARD();
+    bool unselected = target_combined_binary() && !target_info();
+    const char *match = NULL;
+    g_autoptr(GString) hints = NULL;
+    unsigned count = 0;
     int i;
 
+    if (unselected) {
+        hints = g_string_new(NULL);
+    }
     for (i = 0; qdev_alias_table[i].alias; i++) {
         if (qdev_alias_table[i].arch_mask &&
             !qemu_arch_available(qdev_alias_table[i].arch_mask)) {
@@ -228,11 +238,32 @@ static const char *find_typename_by_alias(const char 
*alias)
         }
 
         if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
-            return qdev_alias_table[i].typename;
+            const char *typename = qdev_alias_table[i].typename;
+
+            if (!unselected) {
+                return typename;
+            }
+            ObjectClass *oc = module_object_class_by_name(typename);
+
+            if (!object_class_dynamic_cast(oc, TYPE_DEVICE) ||
+                object_class_is_abstract(oc)) {
+                continue;
+            }
+            match = typename;
+            count++;
+            g_string_append_printf(hints, "  %s\n", typename);
         }
     }
 
-    return NULL;
+    if (count > 1) {
+        error_setg(errp, "Device alias '%s' is ambiguous without a "
+                   "selected machine", alias);
+        error_append_hint(errp, "Specify -machine <arch>-<machine-name> or "
+                          "an unambiguous <machine-name>, or use a "
+                          "concrete device name:\n%s", hints->str);
+        return NULL;
+    }
+    return match;
 }
 
 static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
@@ -243,7 +274,13 @@ static DeviceClass *qdev_get_device_class(const char 
**driver, Error **errp)
 
     oc = module_object_class_by_name(*driver);
     if (!oc) {
-        const char *typename = find_typename_by_alias(*driver);
+        Error *local_err = NULL;
+        const char *typename = find_typename_by_alias(*driver, &local_err);
+
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return NULL;
+        }
 
         if (typename) {
             *driver = typename;
@@ -308,7 +345,12 @@ int qdev_device_help(QemuOpts *opts)
     }
 
     if (!object_class_by_name(driver)) {
-        const char *typename = find_typename_by_alias(driver);
+        const char *typename = find_typename_by_alias(driver, &local_err);
+
+        if (local_err) {
+            error_report_err(local_err);
+            return -1;
+        }
 
         if (typename) {
             driver = typename;
diff --git a/system/vl.c b/system/vl.c
index bad13393f24..068fa5e12ad 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -2795,9 +2795,10 @@ static void qemu_process_help_options(void)
         exit(0);
     }
 
-    if (qemu_opts_foreach(qemu_find_opts("device"),
-                          device_help_func, NULL, NULL)) {
-        exit(0);
+    int device_help = qemu_opts_foreach(qemu_find_opts("device"),
+                                      device_help_func, NULL, NULL);
+    if (device_help) {
+        exit(device_help < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
     }
 
     /* -L help lists the data directories and exits. */
-- 
2.55.0.windows.3


Reply via email to