From: Karel Zak Date: Thu, 9 Dec 2021 12:20:50 +0000 (+0100) Subject: findmnt: add SOURCES column to print all devices with the same tag X-Git-Tag: v2.38-rc1~98 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fd2ae1e1b03cb8e9a76aa55c47769991f7dd5d4d;p=thirdparty%2Futil-linux.git findmnt: add SOURCES column to print all devices with the same tag It's the same like TARGETS for lsblk (the same device is possible to mount on more mountpoints). Here in findmnt we support by a new column SOURCES scenario when more devices (filesystems) use the same tag (LABEL, UUID, e.g.). For example: $ findmnt --fstab -oTARGET,SOURCES --evaluate --json UUID=b45897ca-ffc4-4089-8404-5d6072f5aee1 { "filesystems": [ { "target": "/mnt/test", "sources": [ "/dev/sdb1", "/dev/sdc" ] } ] } Fixes: https://github.com/util-linux/util-linux/issues/1078 Signed-off-by: Karel Zak --- diff --git a/misc-utils/findmnt.8.adoc b/misc-utils/findmnt.8.adoc index 7614ec2332..09a9ff549f 100644 --- a/misc-utils/findmnt.8.adoc +++ b/misc-utils/findmnt.8.adoc @@ -56,7 +56,7 @@ Imitate the output of *df*(1). This option is equivalent to *-o SOURCE,FSTYPE,SI The search direction, either *forward* or *backward*. *-e*, *--evaluate*:: -Convert all tags (LABEL, UUID, PARTUUID or PARTLABEL) to the corresponding device names. +Convert all tags (LABEL, UUID, PARTUUID, or PARTLABEL) to the corresponding device names for the SOURCE column. It's an unusual situation, but the same tag may be duplicated (used for more devices). For this purpose, there is SOURCES (pl.) column. This column displays by multi-line cell all devices where the tag is detected by libblkid. This option makes sense for fstab only. *-F*, *--tab-file* _path_:: Search in an alternative file. If used with *--fstab*, *--mtab* or *--kernel*, then it overrides the default paths. If specified more than once, then tree-like output is disabled (see the *--list* option). diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c index 815203778b..4fcd117004 100644 --- a/misc-utils/findmnt.c +++ b/misc-utils/findmnt.c @@ -35,6 +35,7 @@ #ifdef HAVE_LIBUDEV # include #endif +#include #include #include @@ -46,6 +47,7 @@ #include "xalloc.h" #include "optutils.h" #include "mangle.h" +#include "buffer.h" #include "findmnt.h" @@ -72,6 +74,7 @@ enum { COL_PROPAGATION, COL_SIZE, COL_SOURCE, + COL_SOURCES, COL_TARGET, COL_TID, COL_USED, @@ -118,6 +121,7 @@ static struct colinfo infos[] = { [COL_PASSNO] = { "PASSNO", 1, SCOLS_FL_RIGHT, N_("pass number on parallel fsck(8) [fstab only]") }, [COL_PROPAGATION] = { "PROPAGATION", 0.10, 0, N_("VFS propagation flags") }, [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("filesystem size") }, + [COL_SOURCES] = { "SOURCES", 0.25, SCOLS_FL_WRAP, N_("all possible source devices [fstab only]") }, [COL_SOURCE] = { "SOURCE", 0.25, SCOLS_FL_NOEXTREMES, N_("source device") }, [COL_TARGET] = { "TARGET", 0.30, SCOLS_FL_TREE| SCOLS_FL_NOEXTREMES, N_("mountpoint") }, [COL_TID] = { "TID", 4, SCOLS_FL_RIGHT, N_("task ID") }, @@ -511,9 +515,41 @@ static char *get_vfs_attr(struct libmnt_fs *fs, int sizetype) static char *get_data(struct libmnt_fs *fs, int num) { char *str = NULL; + const char *t = NULL, *v = NULL; int col_id = get_column_id(num); switch (col_id) { + case COL_SOURCES: + /* print all devices with the same tag (LABEL, UUID) */ + if ((flags & FL_EVALUATE) && + mnt_fs_get_tag(fs, &t, &v) == 0) { + blkid_dev_iterate iter; + blkid_dev dev; + blkid_cache cache = NULL; + struct ul_buffer buf = UL_INIT_BUFFER; + int i = 0; + + if (blkid_get_cache(&cache, NULL) < 0) + break; + + blkid_probe_all(cache); + + iter = blkid_dev_iterate_begin(cache); + blkid_dev_set_search(iter, t, v); + while (blkid_dev_next(iter, &dev) == 0) { + dev = blkid_verify(cache, dev); + if (!dev) + continue; + if (i != 0) + ul_buffer_append_data(&buf, "\n", 1); + ul_buffer_append_string(&buf, blkid_dev_devname(dev)); + i++; + } + blkid_dev_iterate_end(iter); + str = ul_buffer_get_data(&buf, NULL, NULL); + break; + } + /* fallthrough */ case COL_SOURCE: { const char *root = mnt_fs_get_root(fs); @@ -536,6 +572,7 @@ static char *get_data(struct libmnt_fs *fs, int num) free(cn); break; } + case COL_TARGET: if (mnt_fs_get_target(fs)) str = xstrdup(mnt_fs_get_target(fs)); @@ -1716,7 +1753,14 @@ int main(int argc, char *argv[]) warn(_("failed to allocate output column")); goto leave; } - + /* multi-line cells (now used for SOURCES) */ + if (fl & SCOLS_FL_WRAP) { + scols_column_set_wrapfunc(cl, + scols_wrapnl_chunksize, + scols_wrapnl_nextchunk, + NULL); + scols_column_set_safechars(cl, "\n"); + } if (flags & FL_JSON) { switch (id) { case COL_SIZE: @@ -1736,7 +1780,10 @@ int main(int argc, char *argv[]) scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN); break; default: - scols_column_set_json_type(cl, SCOLS_JSON_STRING); + if (fl & SCOLS_FL_WRAP) + scols_column_set_json_type(cl, SCOLS_JSON_ARRAY_STRING); + else + scols_column_set_json_type(cl, SCOLS_JSON_STRING); break; } }