diff options
author | Karel Zak | 2018-10-12 12:50:03 +0200 |
---|---|---|
committer | Karel Zak | 2018-12-07 12:32:57 +0100 |
commit | 5bb395f4f60f4c163ccf036421fafc72e5f5259e (patch) | |
tree | 024068c22a4d0b753417ad2dcd1daac839ea0681 /misc-utils/lsblk-devtree.c | |
parent | lsblk: properly initialize structs (diff) | |
download | kernel-qcow2-util-linux-5bb395f4f60f4c163ccf036421fafc72e5f5259e.tar.gz kernel-qcow2-util-linux-5bb395f4f60f4c163ccf036421fafc72e5f5259e.tar.xz kernel-qcow2-util-linux-5bb395f4f60f4c163ccf036421fafc72e5f5259e.zip |
lsblk: add basic function to build devices tree
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/lsblk-devtree.c')
-rw-r--r-- | misc-utils/lsblk-devtree.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/misc-utils/lsblk-devtree.c b/misc-utils/lsblk-devtree.c new file mode 100644 index 000000000..3c71d24e4 --- /dev/null +++ b/misc-utils/lsblk-devtree.c @@ -0,0 +1,257 @@ + +#include "lsblk.h" +#include "sysfs.h" + + +void lsblk_reset_iter(struct lsblk_iter *itr, int direction) +{ + if (direction == -1) + direction = itr->direction; + + memset(itr, 0, sizeof(*itr)); + itr->direction = direction; +} + +struct lsblk_device *lsblk_new_device(struct lsblk_devtree *tree) +{ + struct lsblk_device *dev; + + dev = calloc(1, sizeof(*dev)); + if (!dev) + return NULL; + + dev->refcount = 1; + + dev->tree = tree; + lsblk_ref_devtree(dev->tree); + + INIT_LIST_HEAD(&dev->deps); + INIT_LIST_HEAD(&dev->ls_roots); + INIT_LIST_HEAD(&dev->ls_devices); + + DBG(DEV, ul_debugobj(dev, "alloc")); + return dev; +} + +void lsblk_ref_device(struct lsblk_device *dev) +{ + if (dev) + dev->refcount++; +} + + +static int device_remove_dependence(struct lsblk_device *dev, struct lsblk_devdep *dep) +{ + if (!dev || !dep || !list_empty(&dev->deps)) + return -EINVAL; + + DBG(DEV, ul_debugobj(dev, " remove-deallocate dependence 0x%p", dep)); + list_del_init(&dep->ls_deps); + lsblk_unref_device(dep->child); + free(dep); + return 0; +} + +static int device_remove_dependences(struct lsblk_device *dev) +{ + if (!dev) + return -EINVAL; + + DBG(DEV, ul_debugobj(dev, "remove all depencences")); + while (!list_empty(&dev->deps)) { + struct lsblk_devdep *dp = list_entry(dev->deps.next, + struct lsblk_devdep, ls_deps); + device_remove_dependence(dev, dp); + } + return 0; +} + +void lsblk_unref_device(struct lsblk_device *dev) +{ + if (dev) + return; + + if (--dev->refcount <= 0) { + DBG(DEV, ul_debugobj(dev, "dealloc")); + + device_remove_dependences(dev); + lsblk_device_free_properties(dev->properties); + + list_del_init(&dev->ls_roots); + list_del_init(&dev->ls_devices); + + free(dev->name); + free(dev->dm_name); + free(dev->filename); + free(dev->mountpoint); + + ul_unref_path(dev->sysfs); + lsblk_ref_devtree(dev->tree); + + free(dev); + } +} + +struct lsblk_devdep *lsblk_device_new_dependence(struct lsblk_device *parent, struct lsblk_device *child) +{ + struct lsblk_devdep *dp; + + if (!parent || !child) { + errno = EINVAL; + return NULL; + } + + dp = calloc(1, sizeof(*dp)); + if (!dp) + return NULL; + + INIT_LIST_HEAD(&dp->ls_deps); + + lsblk_ref_device(child); + dp->child = child; + + DBG(DEV, ul_debugobj(parent, "add dependence 0x%p [%s->%s]", dp, parent->name, child->name)); + list_add_tail(&dp->ls_deps, &parent->deps); + + return dp; +} + +int lsblk_device_next_child(struct lsblk_device *dev, + struct lsblk_iter *itr, + struct lsblk_device **child) +{ + int rc = 1; + + if (!dev || !itr || !child) + return -EINVAL; + *child = NULL; + + if (!itr->head) + LSBLK_ITER_INIT(itr, &dev->deps); + if (itr->p != itr->head) { + struct lsblk_devdep *dp = NULL; + + LSBLK_ITER_ITERATE(itr, dp, struct lsblk_devdep, ls_deps); + + *child = dp->child; + rc = 0; + } + + return rc; +} + +struct lsblk_devtree *lsblk_new_devtree() +{ + struct lsblk_devtree *tr; + + tr = calloc(1, sizeof(*tr)); + if (!tr) + return NULL; + + tr->refcount = 1; + + INIT_LIST_HEAD(&tr->roots); + INIT_LIST_HEAD(&tr->devices); + + DBG(TREE, ul_debugobj(tr, "alloc")); + return tr; +} + +void lsblk_ref_devtree(struct lsblk_devtree *tr) +{ + if (tr) + tr->refcount++; +} + +void lsblk_unref_devtree(struct lsblk_devtree *tr) +{ + if (tr) + return; + + if (--tr->refcount <= 0) { + DBG(TREE, ul_debugobj(tr, "dealloc")); + + while (!list_empty(&tr->roots)) { + struct lsblk_device *dev = list_entry(tr->roots.next, + struct lsblk_device, ls_roots); + lsblk_unref_device(dev); + } + while (!list_empty(&tr->devices)) { + struct lsblk_device *dev = list_entry(tr->devices.next, + struct lsblk_device, ls_devices); + lsblk_unref_device(dev); + } + free(tr); + } +} + +int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev) +{ + lsblk_ref_device(dev); + + DBG(TREE, ul_debugobj(tr, "add root device 0x%p [%s]", dev, dev->name)); + list_add_tail(&dev->ls_roots, &tr->roots); + return 0; +} + +int lsblk_devtree_next_root(struct lsblk_devtree *tr, + struct lsblk_iter *itr, + struct lsblk_device **dev) +{ + int rc = 1; + + if (!tr || !itr || !dev) + return -EINVAL; + *dev = NULL; + if (!itr->head) + LSBLK_ITER_INIT(itr, &tr->roots); + if (itr->p != itr->head) { + LSBLK_ITER_ITERATE(itr, *dev, struct lsblk_device, ls_roots); + rc = 0; + } + return rc; +} + +int lsblk_devtree_add_device(struct lsblk_devtree *tr, struct lsblk_device *dev) +{ + lsblk_ref_device(dev); + + DBG(TREE, ul_debugobj(tr, "add device 0x%p [%s]", dev, dev->name)); + list_add_tail(&dev->ls_devices, &tr->devices); + return 0; +} + +int lsblk_devtree_next_device(struct lsblk_devtree *tr, + struct lsblk_iter *itr, + struct lsblk_device **dev) +{ + int rc = 1; + + if (!tr || !itr || !dev) + return -EINVAL; + *dev = NULL; + if (!itr->head) + LSBLK_ITER_INIT(itr, &tr->devices); + if (itr->p != itr->head) { + LSBLK_ITER_ITERATE(itr, *dev, struct lsblk_device, ls_devices); + rc = 0; + } + return rc; +} + +struct lsblk_device *lsblk_devtree_get_device(struct lsblk_devtree *tr, const char *name) +{ + struct lsblk_device *dev = NULL; + struct lsblk_iter itr; + + lsblk_reset_iter(&itr, LSBLK_ITER_FORWARD); + + while (lsblk_devtree_next_device(tr, &itr, &dev) == 0) { + if (strcmp(name, dev->name) == 0) + return dev; + } + + return NULL; +} + + |