summaryrefslogtreecommitdiffstats
path: root/misc-utils
diff options
context:
space:
mode:
authorKarel Zak2018-12-07 12:29:50 +0100
committerKarel Zak2018-12-07 12:57:49 +0100
commit0bd05f5ee4876ffd13c98acd56c2bff9971f28f1 (patch)
treef0635d4af03006fa5cf90c03ee4ed7a32dfd89d9 /misc-utils
parentlibsmartcols: add grouping API docs (diff)
downloadkernel-qcow2-util-linux-0bd05f5ee4876ffd13c98acd56c2bff9971f28f1.tar.gz
kernel-qcow2-util-linux-0bd05f5ee4876ffd13c98acd56c2bff9971f28f1.tar.xz
kernel-qcow2-util-linux-0bd05f5ee4876ffd13c98acd56c2bff9971f28f1.zip
lsblk: add --merge
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils')
-rw-r--r--misc-utils/lsblk-devtree.c34
-rw-r--r--misc-utils/lsblk.828
-rw-r--r--misc-utils/lsblk.c71
-rw-r--r--misc-utils/lsblk.h10
4 files changed, 112 insertions, 31 deletions
diff --git a/misc-utils/lsblk-devtree.c b/misc-utils/lsblk-devtree.c
index c38f3eb1e..82db4f8cf 100644
--- a/misc-utils/lsblk-devtree.c
+++ b/misc-utils/lsblk-devtree.c
@@ -157,7 +157,7 @@ int lsblk_device_new_dependence(struct lsblk_device *parent, struct lsblk_device
list_add_tail(&dp->ls_childs, &parent->childs);
dp->parent = parent;
- list_add_tail(&dp->ls_parents, &parent->parents);
+ list_add_tail(&dp->ls_parents, &child->parents);
DBG(DEV, ul_debugobj(parent, "add dependence 0x%p [%s->%s]", dp, parent->name, child->name));
@@ -198,6 +198,38 @@ int lsblk_device_next_child(struct lsblk_device *dev,
return rc;
}
+int lsblk_device_is_last_parent(struct lsblk_device *dev, struct lsblk_device *parent)
+{
+ struct lsblk_devdep *dp = list_last_entry(
+ &dev->parents,
+ struct lsblk_devdep, ls_parents);
+
+ return dp->parent == parent;
+}
+
+int lsblk_device_next_parent(
+ struct lsblk_device *dev,
+ struct lsblk_iter *itr,
+ struct lsblk_device **parent)
+{
+ int rc = 1;
+
+ if (!dev || !itr || !parent)
+ return -EINVAL;
+ *parent = NULL;
+
+ if (!itr->head)
+ LSBLK_ITER_INIT(itr, &dev->parents);
+ if (itr->p != itr->head) {
+ struct lsblk_devdep *dp = NULL;
+ LSBLK_ITER_ITERATE(itr, dp, struct lsblk_devdep, ls_parents);
+ if (dp)
+ *parent = dp->parent;
+ rc = 0;
+ }
+
+ return rc;
+}
struct lsblk_devtree *lsblk_new_devtree()
{
diff --git a/misc-utils/lsblk.8 b/misc-utils/lsblk.8
index d2a58ed08..2787569fe 100644
--- a/misc-utils/lsblk.8
+++ b/misc-utils/lsblk.8
@@ -51,13 +51,18 @@ Print the SIZE column in bytes rather than in a human-readable format.
.BR \-D , " \-\-discard"
Print information about the discarding capabilities (TRIM, UNMAP) for each device.
.TP
-.BR \-z , " \-\-zoned"
-Print the zone model for each device.
-.TP
.BR \-d , " \-\-nodeps"
Do not print holder devices or slaves. For example, \fBlsblk --nodeps /dev/sda\fR prints
information about the sda device only.
.TP
+.BR \-E , " \-\-dedup " \fIcolumn\fP
+Use \fIcolumn\fP as a de-duplication key to de-duplicate output tree. If the
+key is not available for the device, or the device is a partition and parental
+whole-disk device provides the same key than the device is always printed.
+
+The usual use case is to de-duplicate output on system multi-path devices, for
+example by \fB\-E WWN\fR.
+.TP
.BR \-e , " \-\-exclude " \fIlist\fP
Exclude the devices specified by the comma-separated \fIlist\fR of major device numbers.
Note that RAM disks (major=1) are excluded by default if \fB\-\-all\fR is no specified.
@@ -86,15 +91,13 @@ Use ASCII characters for tree formatting.
Use JSON output format.
.TP
.BR \-l , " \-\-list"
-Produce output in the form of a list.
+Produce output in the form of a list. The output does not provide information
+about relationships between devices and since version 2.34 every device is
+printed only once.
.TP
-.BR \-M , " \-\-dedup " \fIcolumn\fP
-Use \fIcolumn\fP as a de-duplication key to de-duplicate output tree. If the
-key is not available for the device, or the device is a partition and parental
-whole-disk device provides the same key than the device is always printed.
-
-The usual use case is to de-duplicate output on system multi-path devices, for
-example by \fB\-M WWN\fR.
+.BR \-M , " \-\-merge"
+Group parents of sub-trees to provide more readable output for RAIDs and
+Multi-path devices. The tree-like output is required.
.TP
.BR \-m , " \-\-perms"
Output info about device owner, group and mode. This option is equivalent to
@@ -145,6 +148,9 @@ Sort output lines by \fIcolumn\fP. This option enables \fB\-\-list\fR output for
It is possible to use the option \fI\-\-tree\fP to force tree-like output and
than the tree branches are sorted by the \fIcolumn\fP.
.TP
+.BR \-z , " \-\-zoned"
+Print the zone model for each device.
+.TP
.BR " \-\-sysroot " \fIdirectory\fP
Gather data for a Linux instance other than the instance from which the lsblk
command is issued. The specified directory is the system root of the Linux
diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c
index 95c3cdc4d..7ee6dff90 100644
--- a/misc-utils/lsblk.c
+++ b/misc-utils/lsblk.c
@@ -141,7 +141,6 @@ struct colinfo {
double whint; /* width hint (N < 1 is in percent of termwidth) */
int flags; /* SCOLS_FL_* */
const char *help;
-
int type; /* COLTYPE_* */
};
@@ -217,7 +216,6 @@ struct lsblk *lsblk; /* global handler */
static int columns[ARRAY_SIZE(infos) * 2];
static size_t ncolumns;
-
static inline void add_column(int id)
{
if (ncolumns >= ARRAY_SIZE(columns))
@@ -405,7 +403,7 @@ static char *get_type(struct lsblk_device *dev)
{
char *res = NULL, *p;
- if (cxt->partition)
+ if (device_is_partition(dev))
return xstrdup("part");
if (is_dm(dev->name)) {
@@ -701,7 +699,6 @@ static int is_removable_device(struct lsblk_device *dev, struct lsblk_device *pa
/* parent is something else, use sysfs parent */
ul_path_scanf(pc, "removable", "%d", &dev->removable);
}
-
done:
if (dev->removable == -1)
dev->removable = 0;
@@ -718,7 +715,6 @@ static uint64_t device_get_discard_granularity(struct lsblk_device *dev)
return dev->discard_granularity;
}
-
/*
* Generates data (string) for column specified by column ID for specified device. If sortdata
* is not NULL then returns number usable to sort the column if the data are available for the
@@ -1032,13 +1028,42 @@ static void device_to_scols(
struct libscols_line *ln;
struct lsblk_iter itr;
struct lsblk_device *child = NULL;
+ int link_group = 0;
ON_DBG(DEV, if (ul_path_isopen_dirfd(dev->sysfs)) ul_debugobj(dev, "%s ---> is open!", dev->name));
- ln = scols_table_new_line(tab, parent_line);
+ /* Do not print device more than one in --list mode */
+ if (!(lsblk->flags & LSBLK_TREE) && dev->is_printed)
+ return;
+
+ if (lsblk->merge && list_count_entries(&dev->parents) > 1) {
+ if (!lsblk_device_is_last_parent(dev, parent))
+ return;
+ link_group = 1;
+ }
+
+ ln = scols_table_new_line(tab, link_group ? NULL : parent_line);
if (!ln)
err(EXIT_FAILURE, _("failed to allocate output line"));
+ dev->is_printed = 1;
+
+ if (link_group) {
+ struct lsblk_device *p;
+ struct libscols_line *gr = parent_line;
+
+ /* Merge all my parents to the one group */
+ lsblk_reset_iter(&itr, LSBLK_ITER_FORWARD);
+ while (lsblk_device_next_parent(dev, &itr, &p) == 0) {
+ if (!p->scols_line)
+ continue;
+ scols_table_group_lines(tab, gr, p->scols_line, 0);
+ }
+
+ /* Link the group -- this makes group->child connection */
+ scols_line_link_group(ln, gr, 0);
+ }
+
/* read column specific data and set it to smartcols table line */
for (i = 0; i < ncolumns; i++) {
char *data;
@@ -1057,13 +1082,15 @@ static void device_to_scols(
err(EXIT_FAILURE, _("failed to add output data"));
}
+ dev->scols_line = ln;
+
if (dev->npartitions == 0)
/* For partitions we often read from parental whole-disk sysfs,
* otherwise we can close */
ul_path_close_dirfd(dev->sysfs);
- lsblk_reset_iter(&itr, LSBLK_ITER_FORWARD);
+ lsblk_reset_iter(&itr, LSBLK_ITER_FORWARD);
while (lsblk_device_next_child(dev, &itr, &child) == 0)
device_to_scols(child, dev, tab, ln);
@@ -1547,6 +1574,7 @@ static int process_all_devices(struct lsblk_devtree *tr)
DBG(DEV, ul_debug(" %s: ignore (in-middle)", d->d_name));
goto next;
}
+
lsblk_devtree_add_root(tr, dev);
process_dependencies(tr, dev, 1);
next:
@@ -1690,29 +1718,30 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_("List information about block devices.\n"), out);
fputs(USAGE_OPTIONS, out);
+ fputs(_(" -D, --discard print discard capabilities\n"), out);
+ fputs(_(" -E, --dedup <column> de-duplicate output by <column>\n"), out);
+ fputs(_(" -I, --include <list> show only devices with specified major numbers\n"), out);
+ fputs(_(" -J, --json use JSON output format\n"), out);
+ fputs(_(" -O, --output-all output all columns\n"), out);
+ fputs(_(" -P, --pairs use key=\"value\" output format\n"), out);
+ fputs(_(" -S, --scsi output info about SCSI devices\n"), out);
+ fputs(_(" -T, --tree use tree format output\n"), out);
fputs(_(" -a, --all print all devices\n"), out);
fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out);
fputs(_(" -d, --nodeps don't print slaves or holders\n"), out);
- fputs(_(" -D, --discard print discard capabilities\n"), out);
- fputs(_(" -z, --zoned print zone model\n"), out);
fputs(_(" -e, --exclude <list> exclude devices by major number (default: RAM disks)\n"), out);
fputs(_(" -f, --fs output info about filesystems\n"), out);
fputs(_(" -i, --ascii use ascii characters only\n"), out);
- fputs(_(" -I, --include <list> show only devices with specified major numbers\n"), out);
- fputs(_(" -J, --json use JSON output format\n"), out);
fputs(_(" -l, --list use list format output\n"), out);
- fputs(_(" -T, --tree use tree format output\n"), out);
- fputs(_(" -M, --dedup <column> de-duplicate output by <column>\n"), out);
+ fputs(_(" -M, --merge group parents of sub-trees (usable for RAIDs, Multi-path)\n"), out);
fputs(_(" -m, --perms output info about permissions\n"), out);
fputs(_(" -n, --noheadings don't print headings\n"), out);
fputs(_(" -o, --output <list> output columns\n"), out);
- fputs(_(" -O, --output-all output all columns\n"), out);
fputs(_(" -p, --paths print complete device path\n"), out);
- fputs(_(" -P, --pairs use key=\"value\" output format\n"), out);
fputs(_(" -r, --raw use raw output format\n"), out);
fputs(_(" -s, --inverse inverse dependencies\n"), out);
- fputs(_(" -S, --scsi output info about SCSI devices\n"), out);
fputs(_(" -t, --topology output info about topology\n"), out);
+ fputs(_(" -z, --zoned print zone model\n"), out);
fputs(_(" -x, --sort <column> sort output by <column>\n"), out);
fputs(_(" --sysroot <dir> use specified directory as system root\n"), out);
fputs(USAGE_SEPARATOR, out);
@@ -1757,12 +1786,13 @@ int main(int argc, char *argv[])
{ "bytes", no_argument, NULL, 'b' },
{ "nodeps", no_argument, NULL, 'd' },
{ "discard", no_argument, NULL, 'D' },
- { "dedup", required_argument, NULL, 'M' },
+ { "dedup", required_argument, NULL, 'E' },
{ "zoned", no_argument, NULL, 'z' },
{ "help", no_argument, NULL, 'h' },
{ "json", no_argument, NULL, 'J' },
{ "output", required_argument, NULL, 'o' },
{ "output-all", no_argument, NULL, 'O' },
+ { "merge", no_argument, NULL, 'M' },
{ "perms", no_argument, NULL, 'm' },
{ "noheadings", no_argument, NULL, 'n' },
{ "list", no_argument, NULL, 'l' },
@@ -1806,7 +1836,7 @@ int main(int argc, char *argv[])
lsblk_init_debug();
while((c = getopt_long(argc, argv,
- "abdDze:fhJlnmM:o:OpPiI:rstVSTx:", longopts, NULL)) != -1) {
+ "abdDzE:e:fhJlnMmo:OpPiI:rstVSTx:", longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -1843,6 +1873,9 @@ int main(int argc, char *argv[])
case 'l':
lsblk->flags &= ~LSBLK_TREE; /* disable the default */
break;
+ case 'M':
+ lsblk->merge = 1;
+ break;
case 'n':
lsblk->flags |= LSBLK_NOHEADINGS;
break;
@@ -1923,7 +1956,7 @@ int main(int argc, char *argv[])
case 'V':
printf(UTIL_LINUX_VERSION);
return EXIT_SUCCESS;
- case 'M':
+ case 'E':
lsblk->dedup_id = column_name_to_id(optarg, strlen(optarg));
if (lsblk->dedup_id >= 0)
break;
diff --git a/misc-utils/lsblk.h b/misc-utils/lsblk.h
index 8f8a89dfd..a043e7fd7 100644
--- a/misc-utils/lsblk.h
+++ b/misc-utils/lsblk.h
@@ -45,6 +45,7 @@ struct lsblk {
unsigned int all_devices:1; /* print all devices, including empty */
unsigned int bytes:1; /* print SIZE in bytes */
unsigned int inverse:1; /* print inverse dependencies */
+ unsigned int merge:1; /* merge sub-trees */
unsigned int nodeps:1; /* don't print slaves/holders */
unsigned int scsi:1; /* print only device with HCTL (SCSI) */
unsigned int paths:1; /* print devnames with "/dev" prefix */
@@ -93,6 +94,8 @@ struct lsblk_device {
struct lsblk_device *wholedisk; /* for partitions */
+ struct libscols_line *scols_line;
+
struct lsblk_devprop *properties;
struct stat st;
@@ -120,6 +123,7 @@ struct lsblk_device {
unsigned int is_mounted : 1,
is_swap : 1,
+ is_printed : 1,
udev_requested : 1,
blkid_requested : 1;
};
@@ -196,6 +200,12 @@ int lsblk_device_next_child(struct lsblk_device *dev,
struct lsblk_iter *itr,
struct lsblk_device **child);
+int lsblk_device_is_last_parent(struct lsblk_device *dev, struct lsblk_device *parent);
+int lsblk_device_next_parent(
+ struct lsblk_device *dev,
+ struct lsblk_iter *itr,
+ struct lsblk_device **parent);
+
struct lsblk_devtree *lsblk_new_devtree(void);
void lsblk_ref_devtree(struct lsblk_devtree *tr);
void lsblk_unref_devtree(struct lsblk_devtree *tr);