lsblk: add --merge
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
4f4c2b3cdd
commit
0bd05f5ee4
|
@ -43,22 +43,6 @@ lsblk
|
|||
and it may be confusing for end-users when FS to DEV mapping is not 1:1 (RAIDs, btrfs,
|
||||
...)
|
||||
|
||||
- add --merge option to merge the same trees
|
||||
sdb 8:16 0 204M 0 disk
|
||||
└─md127 9:127 0 611.5M 0 raid0
|
||||
sdc 8:32 0 204M 0 disk
|
||||
└─md127 9:127 0 611.5M 0 raid0
|
||||
sdd 8:48 0 204M 0 disk
|
||||
└─md127 9:127 0 611.5M 0 raid0
|
||||
to
|
||||
sdb| 8:16 0 204M 0 disk
|
||||
sdc| 8:32 0 204M 0 disk
|
||||
sdd| 8:48 0 204M 0 disk
|
||||
└─md127 9:127 0 611.5M 0 raid0
|
||||
|
||||
This feature will require change to libsmartcols to support "multi-parent"
|
||||
output formatting (more than one parent).
|
||||
|
||||
nsenter(1)
|
||||
----------
|
||||
- read the default UID and GID from the target process.
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue