lsblk: print all device mountpoints
* add libmount FS to struct lsblk_device * add new column MOUNTPOINTS (pl.) with multi-line cells to display all mountpoints relevant for the device * the old MOUNTPOINT is backwardly compatible and it (usually) displays the last device mountpoint from /proc/self/mountinfo For example btrfs with more subvolumes: $ lsblk -o+MOUNTPOINTS /dev/sdc1 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT MOUNTPOINTS sdc1 8:33 0 50M 0 part /mnt/test /mnt/A /mnt/test /mnt/B Note, in this case MOUNTPOINT displays mount point where is mounted root of the filesystem. Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
3c7355dd63
commit
c6648d2db1
|
@ -106,12 +106,12 @@ void lsblk_unref_device(struct lsblk_device *dev)
|
|||
|
||||
device_remove_dependences(dev);
|
||||
lsblk_device_free_properties(dev->properties);
|
||||
lsblk_device_free_filesystems(dev);
|
||||
|
||||
lsblk_unref_device(dev->wholedisk);
|
||||
|
||||
free(dev->dm_name);
|
||||
free(dev->filename);
|
||||
free(dev->mountpoint);
|
||||
free(dev->dedupkey);
|
||||
|
||||
ul_unref_path(dev->sysfs);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
#include "xalloc.h"
|
||||
#include "nls.h"
|
||||
|
||||
#include <libmount.h>
|
||||
|
||||
#include "lsblk.h"
|
||||
|
||||
static struct libmnt_table *mtab, *swaps;
|
||||
|
@ -18,8 +16,10 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int is_active_swap(const char *filename)
|
||||
static struct libmnt_fs *get_active_swap(const char *filename)
|
||||
{
|
||||
assert(filename);
|
||||
|
||||
if (!swaps) {
|
||||
swaps = mnt_new_table();
|
||||
if (!swaps)
|
||||
|
@ -39,19 +39,46 @@ static int is_active_swap(const char *filename)
|
|||
}
|
||||
}
|
||||
|
||||
return mnt_table_find_srcpath(swaps, filename, MNT_ITER_BACKWARD) != NULL;
|
||||
return mnt_table_find_srcpath(swaps, filename, MNT_ITER_BACKWARD);
|
||||
}
|
||||
|
||||
char *lsblk_device_get_mountpoint(struct lsblk_device *dev)
|
||||
void lsblk_device_free_filesystems(struct lsblk_device *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
free(dev->fss);
|
||||
|
||||
dev->fss = NULL;
|
||||
dev->nfss = 0;
|
||||
dev->is_mounted = 0;
|
||||
dev->is_swap = 0;
|
||||
}
|
||||
|
||||
static void add_filesystem(struct lsblk_device *dev, struct libmnt_fs *fs)
|
||||
{
|
||||
assert(dev);
|
||||
assert(fs);
|
||||
|
||||
dev->fss = xrealloc(dev->fss, dev->nfss + 1 * sizeof(struct libmnt_fs *));
|
||||
dev->fss[dev->nfss] = fs;
|
||||
dev->nfss++;
|
||||
dev->is_mounted = 1;
|
||||
}
|
||||
|
||||
struct libmnt_fs **lsblk_device_get_filesystems(struct lsblk_device *dev, size_t *n)
|
||||
{
|
||||
struct libmnt_fs *fs;
|
||||
const char *fsroot;
|
||||
struct libmnt_iter *itr = NULL;
|
||||
dev_t devno;
|
||||
|
||||
assert(dev);
|
||||
assert(dev->filename);
|
||||
|
||||
if (dev->is_mounted || dev->is_swap)
|
||||
return dev->mountpoint;
|
||||
if (dev->is_mounted)
|
||||
goto done;
|
||||
|
||||
lsblk_device_free_filesystems(dev); /* reset */
|
||||
|
||||
if (!mtab) {
|
||||
mtab = mnt_new_table();
|
||||
|
@ -72,46 +99,72 @@ char *lsblk_device_get_mountpoint(struct lsblk_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Note that maj:min in /proc/self/mountinfo does not have to match with
|
||||
* devno as returned by stat(), so we have to try devname too
|
||||
*/
|
||||
fs = mnt_table_find_devno(mtab, makedev(dev->maj, dev->min), MNT_ITER_BACKWARD);
|
||||
if (!fs)
|
||||
fs = mnt_table_find_srcpath(mtab, dev->filename, MNT_ITER_BACKWARD);
|
||||
if (!fs) {
|
||||
if (is_active_swap(dev->filename)) {
|
||||
dev->mountpoint = xstrdup("[SWAP]");
|
||||
dev->is_swap = 1;
|
||||
} else
|
||||
dev->mountpoint = NULL;
|
||||
devno = makedev(dev->maj, dev->min);
|
||||
|
||||
return dev->mountpoint;
|
||||
/* All mounpoint where is used devno or device name
|
||||
*/
|
||||
itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
||||
while (mnt_table_next_fs(mtab, itr, &fs) == 0) {
|
||||
if (mnt_fs_get_devno(fs) != devno &&
|
||||
!mnt_fs_streq_srcpath(fs, dev->filename))
|
||||
continue;
|
||||
add_filesystem(dev, fs);
|
||||
}
|
||||
|
||||
/* found */
|
||||
fsroot = mnt_fs_get_root(fs);
|
||||
if (fsroot && strcmp(fsroot, "/") != 0) {
|
||||
/* hmm.. we found bind mount or btrfs subvolume, let's try to
|
||||
* get real FS root mountpoint */
|
||||
struct libmnt_fs *rfs;
|
||||
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
||||
/* Try mnt_table_find_srcpath() which also cannonicalize patchs, etc.
|
||||
*/
|
||||
if (!dev->nfss) {
|
||||
fs = get_active_swap(dev->filename);
|
||||
if (!fs) {
|
||||
fs = mnt_table_find_srcpath(mtab, dev->filename, MNT_ITER_BACKWARD);
|
||||
if (fs)
|
||||
dev->is_swap = 1;
|
||||
}
|
||||
if (fs)
|
||||
add_filesystem(dev, fs);
|
||||
}
|
||||
|
||||
mnt_table_set_iter(mtab, itr, fs);
|
||||
while (mnt_table_next_fs(mtab, itr, &rfs) == 0) {
|
||||
fsroot = mnt_fs_get_root(rfs);
|
||||
if ((!fsroot || strcmp(fsroot, "/") == 0)
|
||||
&& mnt_fs_match_source(rfs, dev->filename, mntcache)) {
|
||||
fs = rfs;
|
||||
done:
|
||||
mnt_free_iter(itr);
|
||||
if (n)
|
||||
*n = dev->nfss;
|
||||
return dev->fss;
|
||||
}
|
||||
|
||||
/* Returns mounpoint where the device is mounted. If the device is used for
|
||||
* more filesystems (subvolumes, ...) than returns the "best" one.
|
||||
*/
|
||||
const char *lsblk_device_get_mountpoint(struct lsblk_device *dev)
|
||||
{
|
||||
struct libmnt_fs *fs = NULL;
|
||||
const char *root;
|
||||
|
||||
lsblk_device_get_filesystems(dev, NULL);
|
||||
if (!dev->nfss)
|
||||
return NULL;
|
||||
|
||||
/* lsblk_device_get_filesystems() scans mountinfo/swaps in backward
|
||||
* order. It means the first in fss[] is the last mounted FS. Let's
|
||||
* keep it as default */
|
||||
fs = dev->fss[0];
|
||||
root = mnt_fs_get_root(fs);
|
||||
|
||||
if (root && strcmp(root, "/") != 0) {
|
||||
/* FS is subvolume (or subdirectory bind-mount). Try to get
|
||||
* FS with "/" root */
|
||||
size_t i;
|
||||
|
||||
for (i = 1; i < dev->nfss; i++) {
|
||||
root = mnt_fs_get_root(dev->fss[i]);
|
||||
if (!root || strcmp(root, "/") == 0) {
|
||||
fs = dev->fss[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
mnt_free_iter(itr);
|
||||
}
|
||||
|
||||
DBG(DEV, ul_debugobj(dev, "mountpoint: %s", mnt_fs_get_target(fs)));
|
||||
dev->mountpoint = xstrdup(mnt_fs_get_target(fs));
|
||||
dev->is_mounted = 1;
|
||||
return dev->mountpoint;
|
||||
if (mnt_fs_is_swaparea(fs))
|
||||
return "[SWAP]";
|
||||
return mnt_fs_get_target(fs);
|
||||
}
|
||||
|
||||
void lsblk_mnt_init(void)
|
||||
|
|
|
@ -46,6 +46,15 @@ case it is recommended to use
|
|||
before
|
||||
.B lsblk
|
||||
to synchronize with udev.
|
||||
.PP
|
||||
The relationship between block devices and filesystems is not always one-to-one.
|
||||
The filesystem may use more block devices, or the same filesystem may be accessible
|
||||
by more paths. This is the reason why
|
||||
.B lsblk
|
||||
provides MOUNTPOINT and MOUNTPOINTS (pl.) columns. The column MOUNTPOINT displays
|
||||
only one mount point (usually the last mounted instance of the filesystem), and
|
||||
the column MOUNTPOINTS displays by multi-line cell all mount points associated
|
||||
with the device.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-a , " \-\-all"
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "optutils.h"
|
||||
#include "fileutils.h"
|
||||
#include "loopdev.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "lsblk.h"
|
||||
|
||||
|
@ -75,6 +76,7 @@ enum {
|
|||
COL_FSUSEPERC,
|
||||
COL_FSVERSION,
|
||||
COL_TARGET,
|
||||
COL_TARGETS,
|
||||
COL_LABEL,
|
||||
COL_UUID,
|
||||
COL_PTUUID,
|
||||
|
@ -165,6 +167,8 @@ static struct colinfo infos[] = {
|
|||
[COL_FSVERSION] = { "FSVER", 0.1, SCOLS_FL_TRUNC, N_("filesystem version") },
|
||||
|
||||
[COL_TARGET] = { "MOUNTPOINT", 0.10, SCOLS_FL_TRUNC, N_("where the device is mounted") },
|
||||
[COL_TARGETS] = { "MOUNTPOINTS", 0.10, SCOLS_FL_WRAP, N_("all locations where device is mounted") },
|
||||
|
||||
[COL_LABEL] = { "LABEL", 0.1, 0, N_("filesystem LABEL") },
|
||||
[COL_UUID] = { "UUID", 36, 0, N_("filesystem UUID") },
|
||||
|
||||
|
@ -620,10 +624,9 @@ static char *get_vfs_attribute(struct lsblk_device *dev, int id)
|
|||
{
|
||||
char *sizestr;
|
||||
uint64_t vfs_attr = 0;
|
||||
char *mnt;
|
||||
|
||||
if (!dev->fsstat.f_blocks) {
|
||||
mnt = lsblk_device_get_mountpoint(dev);
|
||||
const char *mnt = lsblk_device_get_mountpoint(dev);
|
||||
if (!mnt || dev->is_swap)
|
||||
return NULL;
|
||||
if (statvfs(mnt, &dev->fsstat) != 0)
|
||||
|
@ -799,11 +802,27 @@ static char *device_get_data(
|
|||
break;
|
||||
case COL_TARGET:
|
||||
{
|
||||
char *s = lsblk_device_get_mountpoint(dev);
|
||||
if (s)
|
||||
str = xstrdup(s);
|
||||
const char *p = lsblk_device_get_mountpoint(dev);
|
||||
if (p)
|
||||
str = xstrdup(p);
|
||||
break;
|
||||
}
|
||||
case COL_TARGETS:
|
||||
{
|
||||
size_t i, n = 0;
|
||||
struct ul_buffer buf = UL_INIT_BUFFER;
|
||||
struct libmnt_fs **fss = lsblk_device_get_filesystems(dev, &n);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct libmnt_fs *fs = fss[i];
|
||||
if (mnt_fs_is_swaparea(fs))
|
||||
ul_buffer_append_string(&buf, "[SWAP]");
|
||||
else
|
||||
str = NULL;
|
||||
ul_buffer_append_string(&buf, mnt_fs_get_target(fs));
|
||||
if (i + 1 < n)
|
||||
ul_buffer_append_data(&buf, "\n", 1);
|
||||
}
|
||||
str = ul_buffer_get_data(&buf);
|
||||
break;
|
||||
}
|
||||
case COL_LABEL:
|
||||
|
@ -2182,6 +2201,15 @@ int main(int argc, char *argv[])
|
|||
ci->type == COLTYPE_SORTNUM ? cmp_u64_cells : scols_cmpstr_cells,
|
||||
NULL);
|
||||
}
|
||||
/* multi-line cells (now used for MOUNTPOINTS) */
|
||||
if (fl & SCOLS_FL_WRAP) {
|
||||
scols_column_set_wrapfunc(cl,
|
||||
scols_wrapnl_chunksize,
|
||||
scols_wrapnl_nextchunk,
|
||||
NULL);
|
||||
scols_column_set_safechars(cl, "\n");
|
||||
}
|
||||
|
||||
if (lsblk->flags & LSBLK_JSON) {
|
||||
switch (ci->type) {
|
||||
case COLTYPE_SIZE:
|
||||
|
@ -2195,6 +2223,9 @@ int main(int argc, char *argv[])
|
|||
scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <sys/statvfs.h>
|
||||
|
||||
#include <libsmartcols.h>
|
||||
#include <libmount.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "list.h"
|
||||
|
@ -33,7 +34,6 @@ UL_DEBUG_DECLARE_MASK(lsblk);
|
|||
|
||||
struct lsblk {
|
||||
struct libscols_table *table; /* output table */
|
||||
|
||||
struct libscols_column *sort_col;/* sort output by this column */
|
||||
|
||||
int sort_id; /* id of the sort column */
|
||||
|
@ -117,7 +117,9 @@ struct lsblk_device {
|
|||
|
||||
struct path_cxt *sysfs;
|
||||
|
||||
char *mountpoint; /* device mountpoint */
|
||||
struct libmnt_fs **fss; /* filesystems attached to the device */
|
||||
size_t nfss; /* number of items in fss[] */
|
||||
|
||||
struct statvfs fsstat; /* statvfs() result */
|
||||
|
||||
int npartitions; /* # of partitions this device has */
|
||||
|
@ -207,7 +209,9 @@ struct lsblk_iter {
|
|||
extern void lsblk_mnt_init(void);
|
||||
extern void lsblk_mnt_deinit(void);
|
||||
|
||||
extern char *lsblk_device_get_mountpoint(struct lsblk_device *dev);
|
||||
extern void lsblk_device_free_filesystems(struct lsblk_device *dev);
|
||||
extern const char *lsblk_device_get_mountpoint(struct lsblk_device *dev);
|
||||
extern struct libmnt_fs **lsblk_device_get_filesystems(struct lsblk_device *dev, size_t *n);
|
||||
|
||||
/* lsblk-properties.c */
|
||||
extern void lsblk_device_free_properties(struct lsblk_devprop *p);
|
||||
|
|
Loading…
Reference in New Issue