*/
#include "lsblk.h"
#include "sysfs.h"
+#include "pathnames.h"
void lsblk_reset_iter(struct lsblk_iter *itr, int direction)
INIT_LIST_HEAD(&tr->roots);
INIT_LIST_HEAD(&tr->devices);
+ INIT_LIST_HEAD(&tr->pktcdvd_map);
DBG(TREE, ul_debugobj(tr, "alloc"));
return 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);
}
}
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)
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)
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,
DIR *dir;
struct dirent *d;
const char *depname;
+ struct lsblk_device *dep = NULL;
assert(dev);
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? */
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;
}
int dedup_id;
+
const char *sysroot;
int flags; /* LSBLK_* */
#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:
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;
};
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,
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);