From: Jan Kiszka <jan.kis...@siemens.com> Allow to specify the device to be removed via device_del not only by ID but also by its full or abbreviated qtree path. For this purpose, qdev_find is introduced which combines walking the qtree with searching for device IDs if required.
Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- hw/qdev.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ qemu-monitor.hx | 10 +++++----- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index b3d375a..df945ed 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -469,7 +469,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name, return NULL; } -static DeviceState *qdev_find_recursive(BusState *bus, const char *id) +static DeviceState *qdev_find_id_recursive(BusState *bus, const char *id) { DeviceState *dev, *ret; BusState *child; @@ -478,7 +478,7 @@ static DeviceState *qdev_find_recursive(BusState *bus, const char *id) if (dev->id && strcmp(dev->id, id) == 0) return dev; QTAILQ_FOREACH(child, &dev->child_bus, sibling) { - ret = qdev_find_recursive(child, id); + ret = qdev_find_id_recursive(child, id); if (ret) { return ret; } @@ -666,6 +666,43 @@ search_dev_bus: } } +static DeviceState *qdev_find(const char *path) +{ + const char *dev_name; + DeviceState *dev; + char *bus_path; + BusState *bus; + + dev_name = strrchr(path, '/'); + if (!dev_name) { + bus = main_system_bus; + dev_name = path; + } else { + dev_name++; + bus_path = qemu_strdup(path); + bus_path[dev_name - path] = 0; + + bus = qbus_find(bus_path); + qemu_free(bus_path); + + if (!bus) { + /* qbus_find already reported the error */ + return NULL; + } + } + dev = qbus_find_dev(bus, dev_name); + if (!dev) { + dev = qdev_find_id_recursive(main_system_bus, path); + if (!dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, dev_name); + if (!monitor_cur_is_qmp()) { + qbus_list_dev(bus); + } + } + } + return dev; +} + void qbus_create_inplace(BusState *bus, BusInfo *info, DeviceState *parent, const char *name) { @@ -824,12 +861,12 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) { - const char *id = qdict_get_str(qdict, "id"); + const char *path = qdict_get_str(qdict, "path"); DeviceState *dev; - dev = qdev_find_recursive(main_system_bus, id); - if (NULL == dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, id); + dev = qdev_find(path); + if (!dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, path); return -1; } return qdev_unplug(dev); diff --git a/qemu-monitor.hx b/qemu-monitor.hx index c8f1789..754d71e 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -703,7 +703,7 @@ EQMP { .name = "device_del", - .args_type = "id:s", + .args_type = "path:s", .params = "device", .help = "remove device", .user_print = monitor_user_noop, @@ -711,10 +711,10 @@ EQMP }, STEXI -...@item device_del @var{id} +...@item device_del @var{path} @findex device_del -Remove device @var{id}. +Remove device @var{path}. ETEXI SQMP device_del @@ -724,11 +724,11 @@ Remove a device. Arguments: -- "id": the device's ID (json-string) +- "path": the device's qtree path or unique ID (json-string) Example: --> { "execute": "device_del", "arguments": { "id": "net1" } } +-> { "execute": "device_del", "arguments": { "path": "net1" } } <- { "return": {} } EQMP -- 1.6.0.2