diff --git a/misc-utils/lsblk-devtree.c b/misc-utils/lsblk-devtree.c index 4d15f70c1..7f39313cd 100644 --- a/misc-utils/lsblk-devtree.c +++ b/misc-utils/lsblk-devtree.c @@ -18,6 +18,7 @@ */ #include "lsblk.h" #include "sysfs.h" +#include "pathnames.h" void lsblk_reset_iter(struct lsblk_iter *itr, int direction) @@ -244,6 +245,7 @@ struct lsblk_devtree *lsblk_new_devtree() INIT_LIST_HEAD(&tr->roots); INIT_LIST_HEAD(&tr->devices); + INIT_LIST_HEAD(&tr->pktcdvd_map); DBG(TREE, ul_debugobj(tr, "alloc")); return tr; @@ -268,6 +270,14 @@ void lsblk_unref_devtree(struct lsblk_devtree *tr) struct lsblk_device, ls_devices); lsblk_devtree_remove_device(tr, dev); } + + while (!list_empty(&tr->pktcdvd_map)) { + struct lsblk_devnomap *map = list_entry(tr->pktcdvd_map.next, + struct lsblk_devnomap, ls_devnomap); + list_del(&map->ls_devnomap); + free(map); + } + free(tr); } } @@ -285,6 +295,15 @@ int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev) return 0; } +int lsblk_devtree_remove_root(struct lsblk_devtree *tr __attribute__((unused)), + struct lsblk_device *dev) +{ + DBG(TREE, ul_debugobj(tr, "remove root device 0x%p [%s]", dev, dev->name)); + list_del_init(&dev->ls_roots); + + return 0; +} + int lsblk_devtree_next_root(struct lsblk_devtree *tr, struct lsblk_iter *itr, struct lsblk_device **dev) @@ -374,6 +393,62 @@ int lsblk_devtree_remove_device(struct lsblk_devtree *tr, struct lsblk_device *d return 0; } +static void read_pktcdvd_map(struct lsblk_devtree *tr) +{ + char buf[PATH_MAX]; + FILE *f; + + assert(tr->pktcdvd_read == 0); + + f = ul_path_fopen(NULL, "r", _PATH_SYS_CLASS "/pktcdvd/device_map"); + if (!f) + goto done; + + while (fgets(buf, sizeof(buf), f)) { + struct lsblk_devnomap *map; + int pkt_maj, pkt_min, blk_maj, blk_min; + + if (sscanf(buf, "%*s %d:%d %d:%d\n", + &pkt_maj, &pkt_min, + &blk_maj, &blk_min) != 4) + continue; + + map = malloc(sizeof(*map)); + if (!map) + break; + map->holder = makedev(pkt_maj, pkt_min); + map->slave = makedev(blk_maj, blk_min); + INIT_LIST_HEAD(&map->ls_devnomap); + list_add_tail(&map->ls_devnomap, &tr->pktcdvd_map); + } + + fclose(f); +done: + tr->pktcdvd_read = 1; +} + +/* returns opposite device of @devno for blk->pkt relation -- e.g. if devno + * is_slave (blk) then returns holder (pkt) and vice-versa */ +dev_t lsblk_devtree_pktcdvd_get_mate(struct lsblk_devtree *tr, dev_t devno, int is_slave) +{ + struct list_head *p; + + if (!tr->pktcdvd_read) + read_pktcdvd_map(tr); + if (list_empty(&tr->pktcdvd_map)) + return 0; + + list_for_each(p, &tr->pktcdvd_map) { + struct lsblk_devnomap *x = list_entry(p, struct lsblk_devnomap, ls_devnomap); + + if (is_slave && devno == x->slave) + return x->holder; + if (!is_slave && devno == x->holder) + return x->slave; + } + return 0; +} + static int device_dedupkey_is_equal( struct lsblk_device *dev, struct lsblk_device *pattern) diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c index 03456b81c..210a36633 100644 --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@ -1267,6 +1267,26 @@ static struct lsblk_device *devtree_get_device_or_new(struct lsblk_devtree *tr, return dev; } +static struct lsblk_device *devtree_pktcdvd_get_dep( + struct lsblk_devtree *tr, + struct lsblk_device *dev, + int want_slave) +{ + char buf[PATH_MAX], *name; + dev_t devno; + + devno = lsblk_devtree_pktcdvd_get_mate(tr, + makedev(dev->maj, dev->min), !want_slave); + if (!devno) + return NULL; + + name = sysfs_devno_to_devname(devno, buf, sizeof(buf)); + if (!name) + return NULL; + + return devtree_get_device_or_new(tr, NULL, name); +} + static int process_dependencies( struct lsblk_devtree *tr, struct lsblk_device *dev, @@ -1357,6 +1377,7 @@ static int process_dependencies( DIR *dir; struct dirent *d; const char *depname; + struct lsblk_device *dep = NULL; assert(dev); @@ -1371,21 +1392,20 @@ static int process_dependencies( if (!(lsblk->inverse ? dev->nslaves : dev->nholders)) { DBG(DEV, ul_debugobj(dev, " ignore (no slaves/holders)")); - return 0; + goto done; } depname = lsblk->inverse ? "slaves" : "holders"; dir = ul_path_opendir(dev->sysfs, depname); if (!dir) { DBG(DEV, ul_debugobj(dev, " ignore (no slaves/holders directory)")); - return 0; + goto done; } ul_path_close_dirfd(dev->sysfs); DBG(DEV, ul_debugobj(dev, " %s: checking for '%s' dependence", dev->name, depname)); while ((d = xreaddir(dir))) { - struct lsblk_device *dep = NULL; struct lsblk_device *disk = NULL; /* Is the dependency a partition? */ @@ -1436,8 +1456,14 @@ next: ul_path_close_dirfd(disk->sysfs); } closedir(dir); +done: + dep = devtree_pktcdvd_get_dep(tr, dev, lsblk->inverse); + + if (dep && lsblk_device_new_dependence(dev, dep) == 0) { + lsblk_devtree_remove_root(tr, dep); + process_dependencies(tr, dep, lsblk->inverse ? 0 : 1); + } - DBG(DEV, ul_debugobj(dev, "%s: checking for '%s' -- done", dev->name, depname)); return 0; } diff --git a/misc-utils/lsblk.h b/misc-utils/lsblk.h index 87221271e..17708b4d5 100644 --- a/misc-utils/lsblk.h +++ b/misc-utils/lsblk.h @@ -41,6 +41,7 @@ struct lsblk { int dedup_id; + const char *sysroot; int flags; /* LSBLK_* */ @@ -140,6 +141,18 @@ struct lsblk_device { #define device_is_partition(_x) ((_x)->wholedisk != NULL) +/* Unfortunately, pktcdvd dependence on block device is not defined by + * slave/holder symlinks. The struct lsblk_devnomap represents one line in + * /sys/class/pktcdvd/device_map + */ +struct lsblk_devnomap { + dev_t slave; /* packet device devno */ + dev_t holder; /* block device devno */ + + struct list_head ls_devnomap; +}; + + /* * Note that lsblk tree uses bottom devices (devices without slaves) as root * of the tree, and partitions are interpreted as a dependence too; it means: @@ -153,8 +166,10 @@ struct lsblk_devtree { struct list_head roots; /* tree root devices */ struct list_head devices; /* all devices */ + struct list_head pktcdvd_map; /* devnomap->ls_devnomap */ - unsigned int is_inverse : 1; /* inverse tree */ + unsigned int is_inverse : 1, /* inverse tree */ + pktcdvd_read : 1; }; @@ -212,6 +227,8 @@ int lsblk_device_next_child(struct lsblk_device *dev, struct lsblk_iter *itr, struct lsblk_device **child); +dev_t lsblk_devtree_pktcdvd_get_mate(struct lsblk_devtree *tr, dev_t devno, int is_slave); + int lsblk_device_is_last_parent(struct lsblk_device *dev, struct lsblk_device *parent); int lsblk_device_next_parent( struct lsblk_device *dev, @@ -222,6 +239,7 @@ struct lsblk_devtree *lsblk_new_devtree(void); void lsblk_ref_devtree(struct lsblk_devtree *tr); void lsblk_unref_devtree(struct lsblk_devtree *tr); int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev); +int lsblk_devtree_remove_root(struct lsblk_devtree *tr, struct lsblk_device *dev); int lsblk_devtree_next_root(struct lsblk_devtree *tr, struct lsblk_iter *itr, struct lsblk_device **dev);