summaryrefslogtreecommitdiff
path: root/hw/qdev.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-12-12 14:29:30 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2011-12-15 09:20:48 -0600
commitdc45c21f39f826e7ab4b8e86fc4d0c987fad3fb7 (patch)
treec87467c8059f86f5d8725754e7183cae1131432a /hw/qdev.c
parentf9fbd2fd0e1ffe666487a072226dd87753db66f9 (diff)
downloadqemu-dc45c21f39f826e7ab4b8e86fc4d0c987fad3fb7.tar.gz
qdev: provide a path resolution (v2)
There are two types of supported paths--absolute paths and partial paths. Absolute paths are derived from the root device and can follow child<> or link<> properties. Since they can follow link<> properties, they can be arbitrarily long. Absolute paths look like absolute filenames and are prefixed with a leading slash. Partial paths are look like relative filenames. They do not begin with a prefix. The matching rules for partial paths are subtle but designed to make specifying devices easy. At each level of the composition tree, the partial path is matched as an absolute path. The first match is not returned. At least two matches are searched for. A successful result is only returned if only one match is founded. If more than one match is found, a flag is returned to indicate that the match was ambiguous. At the end of the day, partial path support means that if you create a device called 'ide0', you can just say 'ide0' as the path name and it will Just Work. If we internally create a device called 'i440fx', you can just say 'i440fx' and it will Just Work and long as you don't do anything silly. A management tool should probably always use absolute paths since then they don't have to deal with the possibility of ambiguity. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/qdev.c')
-rw-r--r--hw/qdev.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/hw/qdev.c b/hw/qdev.c
index 79849c9bfd..2519f00787 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -1221,3 +1221,106 @@ gchar *qdev_get_canonical_path(DeviceState *dev)
return newpath;
}
+
+static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
+ gchar **parts,
+ int index)
+{
+ DeviceProperty *prop;
+ DeviceState *child;
+
+ if (parts[index] == NULL) {
+ return parent;
+ }
+
+ if (strcmp(parts[index], "") == 0) {
+ return qdev_resolve_abs_path(parent, parts, index + 1);
+ }
+
+ prop = qdev_property_find(parent, parts[index]);
+ if (prop == NULL) {
+ return NULL;
+ }
+
+ child = NULL;
+ if (strstart(prop->type, "link<", NULL)) {
+ DeviceState **pchild = prop->opaque;
+ if (*pchild) {
+ child = *pchild;
+ }
+ } else if (strstart(prop->type, "child<", NULL)) {
+ child = prop->opaque;
+ }
+
+ if (!child) {
+ return NULL;
+ }
+
+ return qdev_resolve_abs_path(child, parts, index + 1);
+}
+
+static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
+ gchar **parts,
+ bool *ambiguous)
+{
+ DeviceState *dev;
+ DeviceProperty *prop;
+
+ dev = qdev_resolve_abs_path(parent, parts, 0);
+
+ QTAILQ_FOREACH(prop, &parent->properties, node) {
+ DeviceState *found;
+
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
+ if (found) {
+ if (dev) {
+ if (ambiguous) {
+ *ambiguous = true;
+ }
+ return NULL;
+ }
+ dev = found;
+ }
+
+ if (ambiguous && *ambiguous) {
+ return NULL;
+ }
+ }
+
+ return dev;
+}
+
+DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
+{
+ bool partial_path = true;
+ DeviceState *dev;
+ gchar **parts;
+
+ parts = g_strsplit(path, "/", 0);
+ if (parts == NULL || parts[0] == NULL) {
+ g_strfreev(parts);
+ return qdev_get_root();
+ }
+
+ if (strcmp(parts[0], "") == 0) {
+ partial_path = false;
+ }
+
+ if (partial_path) {
+ if (ambiguous) {
+ *ambiguous = false;
+ }
+ dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
+ } else {
+ dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
+ }
+
+ g_strfreev(parts);
+
+ return dev;
+}
+