diff options
author | Peter Rajnoha | 2012-02-14 09:53:16 +0100 |
---|---|---|
committer | Karel Zak | 2012-03-07 13:54:11 +0100 |
commit | 09a71aa1d5bf373e130131b8c33066bf0542a61b (patch) | |
tree | 5ab7f46d7d78d49591170ddd2d7f14103bec9618 /misc-utils/lsblk.c | |
parent | lsblk: remove (dm-N) from NAME for raw/pair output format (diff) | |
download | kernel-qcow2-util-linux-09a71aa1d5bf373e130131b8c33066bf0542a61b.tar.gz kernel-qcow2-util-linux-09a71aa1d5bf373e130131b8c33066bf0542a61b.tar.xz kernel-qcow2-util-linux-09a71aa1d5bf373e130131b8c33066bf0542a61b.zip |
lsblk: add inverse tree support (-s)
$ lsblk --inverse -o NAME /dev/dm-0
NAME
luks-10d813de-fa82-4f67-a86c-23d5d0e7c30e (dm-0)
└─sda6
└─sda
Signed-off-by: Peter Rajnoha <prajnoha@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/lsblk.c')
-rw-r--r-- | misc-utils/lsblk.c | 214 |
1 files changed, 160 insertions, 54 deletions
diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c index 52833d674..10627d3c7 100644 --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@ -134,6 +134,7 @@ struct lsblk { struct tt *tt; /* output table */ unsigned int all_devices:1; /* print all devices */ unsigned int bytes:1; /* print SIZE in bytes */ + unsigned int inverse:1; /* print inverse dependencies */ unsigned int nodeps:1; /* don't print slaves/holders */ }; @@ -166,8 +167,9 @@ struct blkdev_cxt { char *uuid; /* UUID of device / filesystem */ char *label; /* FS label */ + int npartitions; /* # of partitions this device has */ int nholders; /* # of devices mapped directly to this device - * /sys/block/.../holders + number of partition */ + * /sys/block/.../holders */ int nslaves; /* # of devices this device maps to */ int maj, min; /* devno */ int discard; /* supports discard */ @@ -529,7 +531,7 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line tt_line_set_data(ln, col, xstrdup(cxt->fstype)); break; case COL_TARGET: - if (!cxt->nholders) { + if (!(cxt->nholders + cxt->npartitions)) { p = get_device_mountpoint(cxt); if (p) tt_line_set_data(ln, col, p); @@ -551,8 +553,8 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line break; case COL_RM: p = sysfs_strdup(&cxt->sysfs, "removable"); - if (!p && cxt->parent) - p = sysfs_strdup(&cxt->parent->sysfs, "removable"); + if (!p && cxt->sysfs.parent) + p = sysfs_strdup(cxt->sysfs.parent, "removable"); if (p) tt_line_set_data(ln, col, p); break; @@ -685,14 +687,14 @@ static void print_device(struct blkdev_cxt *cxt, struct tt_line *tt_parent) static int set_cxt(struct blkdev_cxt *cxt, struct blkdev_cxt *parent, - const char *name, - int partition) + struct blkdev_cxt *wholedisk, + const char *name) { dev_t devno; cxt->parent = parent; cxt->name = xstrdup(name); - cxt->partition = partition; + cxt->partition = wholedisk != NULL; cxt->filename = get_device_path(cxt); if (!cxt->filename) { @@ -700,16 +702,25 @@ static int set_cxt(struct blkdev_cxt *cxt, return -1; } - devno = sysfs_devname_to_devno(name, - partition && parent ? parent->name : NULL); + devno = sysfs_devname_to_devno(name, wholedisk ? wholedisk->name : NULL); + if (!devno) { warnx(_("%s: unknown device name"), name); return -1; } - if (sysfs_init(&cxt->sysfs, devno, parent ? &parent->sysfs : NULL)) { - warnx(_("%s: failed to initialize sysfs handler"), name); - return -1; + if (lsblk->inverse) { + if (sysfs_init(&cxt->sysfs, devno, wholedisk ? &wholedisk->sysfs : NULL)) { + warnx(_("%s: failed to initialize sysfs handler"), name); + return -1; + } + if (parent) + parent->sysfs.parent = &cxt->sysfs; + } else { + if (sysfs_init(&cxt->sysfs, devno, parent ? &parent->sysfs : NULL)) { + warnx(_("%s: failed to initialize sysfs handler"), name); + return -1; + } } cxt->maj = major(devno); @@ -731,70 +742,157 @@ static int set_cxt(struct blkdev_cxt *cxt, return -1; } } - cxt->nholders = sysfs_count_dirents(&cxt->sysfs, "holders") + - sysfs_count_partitions(&cxt->sysfs, name); + cxt->npartitions = sysfs_count_partitions(&cxt->sysfs, name); + cxt->nholders = sysfs_count_dirents(&cxt->sysfs, "holders"); cxt->nslaves = sysfs_count_dirents(&cxt->sysfs, "slaves"); return 0; } +static int process_blkdev(struct blkdev_cxt *cxt, struct blkdev_cxt *parent, + int do_partitions, const char *part_name); + /* - * List devices (holders) mapped to device + * List device partitions if any. */ -static int list_holders(struct blkdev_cxt *cxt) +static int list_partitions(struct blkdev_cxt *wholedisk_cxt, struct blkdev_cxt *parent_cxt, + const char *part_name) { DIR *dir; struct dirent *d; - struct blkdev_cxt holder = {}; - - assert(cxt); + struct blkdev_cxt part_cxt = {}; + int r = -1; - if (lsblk->nodeps) - return 0; + assert(wholedisk_cxt); - if (!cxt->nholders) - return 0; + /* + * Do not process further if there are no partitions for + * this device or the device itself is a partition. + */ + if (!wholedisk_cxt->npartitions || wholedisk_cxt->partition) + return -1; - /* Partitions */ - dir = sysfs_opendir(&cxt->sysfs, NULL); + dir = sysfs_opendir(&wholedisk_cxt->sysfs, NULL); if (!dir) err(EXIT_FAILURE, _("failed to open device directory in sysfs")); while ((d = xreaddir(dir))) { - if (!sysfs_is_partition_dirent(dir, d, cxt->name)) + /* Process particular partition only? */ + if (part_name && strcmp(part_name, d->d_name)) continue; - if (set_cxt(&holder, cxt, d->d_name, 1)) { - reset_blkdev_cxt(&holder); + if (!(sysfs_is_partition_dirent(dir, d, wholedisk_cxt->name))) continue; + + if (lsblk->inverse) { + /* + * <parent_cxt> + * `-<part_cxt> + * `-<wholedisk_cxt> + * `-... + */ + if (set_cxt(&part_cxt, parent_cxt, wholedisk_cxt, d->d_name)) + goto next; + + if (!parent_cxt && part_cxt.nholders) + goto next; + + wholedisk_cxt->parent = &part_cxt; + print_device(&part_cxt, parent_cxt ? parent_cxt->tt_line : NULL); + if (!lsblk->nodeps) + process_blkdev(wholedisk_cxt, &part_cxt, 0, NULL); + } else { + /* + * <parent_cxt> + * `-<wholedisk_cxt> + * `-<part_cxt> + * `-... + */ + if (set_cxt(&part_cxt, wholedisk_cxt, wholedisk_cxt, d->d_name)) + goto next; + /* Print whole disk only once */ + if (r) + print_device(wholedisk_cxt, parent_cxt ? parent_cxt->tt_line : NULL); + if (!lsblk->nodeps) + process_blkdev(&part_cxt, wholedisk_cxt, 0, NULL); } - print_device(&holder, cxt->tt_line); - list_holders(&holder); - reset_blkdev_cxt(&holder); + next: + reset_blkdev_cxt(&part_cxt); + r = 0; } + closedir(dir); + return r; +} + +static int get_wholedisk_from_partition_dirent(DIR *dir, struct dirent *d, + struct blkdev_cxt *cxt) +{ + char path[PATH_MAX]; + char *p; + int len; + + if ((len = readlinkat(dirfd(dir), d->d_name, path, sizeof(path))) < 0) + return 0; + path[len]='\0'; + + /* The path ends with ".../<device>/<partition>" */ + p = strrchr(path, '/'); *p = '\0'; + p = strrchr(path, '/'); p++; - /* Holders */ - dir = sysfs_opendir(&cxt->sysfs, "holders"); + return set_cxt(cxt, NULL, NULL, p); +} + +/* + * List device dependencies: partitions, holders (inverse = 0) or slaves (inverse = 1). + */ +static int list_deps(struct blkdev_cxt *cxt) +{ + DIR *dir; + struct dirent *d; + struct blkdev_cxt dep = {}; + + assert(cxt); + + if (lsblk->nodeps) + return 0; + + if (!(lsblk->inverse ? cxt->nslaves : cxt->nholders)) + return 0; + + dir = sysfs_opendir(&cxt->sysfs, lsblk->inverse ? "slaves" : "holders"); if (!dir) return 0; while ((d = xreaddir(dir))) { - if (set_cxt(&holder, cxt, d->d_name, 0)) { - reset_blkdev_cxt(&holder); - continue; + /* Is the dependency a partition? */ + if (sysfs_is_partition_dirent(dir, d, NULL)) { + if (!get_wholedisk_from_partition_dirent(dir, d, &dep)) + process_blkdev(&dep, cxt, 1, d->d_name); } - print_device(&holder, cxt->tt_line); - list_holders(&holder); - reset_blkdev_cxt(&holder); + /* The dependency is a whole device. */ + else if (!set_cxt(&dep, cxt, NULL, d->d_name)) + process_blkdev(&dep, cxt, 1, NULL); + + reset_blkdev_cxt(&dep); } closedir(dir); return 0; } -/* Iterate top-level devices in sysfs */ +static int process_blkdev(struct blkdev_cxt *cxt, struct blkdev_cxt *parent, + int do_partitions, const char *part_name) +{ + if (do_partitions && cxt->npartitions) + return list_partitions(cxt, parent, part_name); + + print_device(cxt, parent ? parent->tt_line : NULL); + return list_deps(cxt); +} + +/* Iterate devices in sysfs */ static int iterate_block_devices(void) { DIR *dir; @@ -805,18 +903,17 @@ static int iterate_block_devices(void) return EXIT_FAILURE; while ((d = xreaddir(dir))) { - if (set_cxt(&cxt, NULL, d->d_name, 0)) + if (set_cxt(&cxt, NULL, NULL, d->d_name)) goto next; - /* Skip devices in the middle of dependence tree */ - if (cxt.nslaves > 0) + if (!lsblk->all_devices && is_maj_excluded(cxt.maj)) goto next; - if (!lsblk->all_devices && is_maj_excluded(cxt.maj)) + /* Skip devices in the middle of dependency tree. */ + if ((lsblk->inverse ? cxt.nholders : cxt.nslaves) > 0) goto next; - print_device(&cxt, NULL); - list_holders(&cxt); + process_blkdev(&cxt, NULL, 1, NULL); next: reset_blkdev_cxt(&cxt); } @@ -844,13 +941,14 @@ static int process_one_device(char *devname) } if (st.st_rdev == disk) { /* - * unpartitioned device + * Device is not a partition. */ - if (set_cxt(&cxt, NULL, buf, 0)) + if (set_cxt(&cxt, NULL, NULL, buf)) goto leave; + process_blkdev(&cxt, NULL, !lsblk->inverse, NULL); } else { /* - * Parititioned, read sysfs name of the device + * Partition, read sysfs name of the device. */ ssize_t len; char path[PATH_MAX], *name; @@ -871,14 +969,17 @@ static int process_one_device(char *devname) /* sysfs device name */ name = strrchr(buf, '/') + 1; - if (set_cxt(&parent, NULL, diskname, 0)) + if (set_cxt(&parent, NULL, NULL, diskname)) goto leave; - if (set_cxt(&cxt, &parent, name, 1)) + if (set_cxt(&cxt, &parent, &parent, name)) goto leave; + + if (lsblk->inverse) + process_blkdev(&parent, &cxt, 1, cxt.name); + else + process_blkdev(&cxt, &parent, 1, NULL); } - print_device(&cxt, NULL); - list_holders(&cxt); status = EXIT_SUCCESS; leave: free(diskname); @@ -938,6 +1039,7 @@ static void __attribute__((__noreturn__)) help(FILE *out) " -o, --output <list> output columns\n" " -P, --pairs use key=\"value\" output format\n" " -r, --raw use raw output format\n" + " -s, --inverse inverse dependencies\n" " -t, --topology output info about topology\n")); fprintf(out, _("\nAvailable columns:\n")); @@ -981,6 +1083,7 @@ int main(int argc, char *argv[]) { "list", 0, 0, 'l' }, { "ascii", 0, 0, 'i' }, { "raw", 0, 0, 'r' }, + { "inverse", 0, 0, 's' }, { "fs", 0, 0, 'f' }, { "exclude", 1, 0, 'e' }, { "topology", 0, 0, 't' }, @@ -995,7 +1098,7 @@ int main(int argc, char *argv[]) lsblk = &_ls; memset(lsblk, 0, sizeof(*lsblk)); - while((c = getopt_long(argc, argv, "abdDe:fhlnmo:Pirt", longopts, NULL)) != -1) { + while((c = getopt_long(argc, argv, "abdDe:fhlnmo:Pirst", longopts, NULL)) != -1) { switch(c) { case 'a': lsblk->all_devices = 1; @@ -1046,6 +1149,9 @@ int main(int argc, char *argv[]) tt_flags &= ~TT_FL_TREE; /* disable the default */ tt_flags |= TT_FL_RAW; /* enable raw */ break; + case 's': + lsblk->inverse = 1; + break; case 'f': columns[ncolumns++] = COL_NAME; columns[ncolumns++] = COL_FSTYPE; |