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);
|
device_remove_dependences(dev);
|
||||||
lsblk_device_free_properties(dev->properties);
|
lsblk_device_free_properties(dev->properties);
|
||||||
|
lsblk_device_free_filesystems(dev);
|
||||||
|
|
||||||
lsblk_unref_device(dev->wholedisk);
|
lsblk_unref_device(dev->wholedisk);
|
||||||
|
|
||||||
free(dev->dm_name);
|
free(dev->dm_name);
|
||||||
free(dev->filename);
|
free(dev->filename);
|
||||||
free(dev->mountpoint);
|
|
||||||
free(dev->dedupkey);
|
free(dev->dedupkey);
|
||||||
|
|
||||||
ul_unref_path(dev->sysfs);
|
ul_unref_path(dev->sysfs);
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "nls.h"
|
#include "nls.h"
|
||||||
|
|
||||||
#include <libmount.h>
|
|
||||||
|
|
||||||
#include "lsblk.h"
|
#include "lsblk.h"
|
||||||
|
|
||||||
static struct libmnt_table *mtab, *swaps;
|
static struct libmnt_table *mtab, *swaps;
|
||||||
|
@ -18,8 +16,10 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_active_swap(const char *filename)
|
static struct libmnt_fs *get_active_swap(const char *filename)
|
||||||
{
|
{
|
||||||
|
assert(filename);
|
||||||
|
|
||||||
if (!swaps) {
|
if (!swaps) {
|
||||||
swaps = mnt_new_table();
|
swaps = mnt_new_table();
|
||||||
if (!swaps)
|
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;
|
struct libmnt_fs *fs;
|
||||||
const char *fsroot;
|
struct libmnt_iter *itr = NULL;
|
||||||
|
dev_t devno;
|
||||||
|
|
||||||
assert(dev);
|
assert(dev);
|
||||||
assert(dev->filename);
|
assert(dev->filename);
|
||||||
|
|
||||||
if (dev->is_mounted || dev->is_swap)
|
if (dev->is_mounted)
|
||||||
return dev->mountpoint;
|
goto done;
|
||||||
|
|
||||||
|
lsblk_device_free_filesystems(dev); /* reset */
|
||||||
|
|
||||||
if (!mtab) {
|
if (!mtab) {
|
||||||
mtab = mnt_new_table();
|
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 = makedev(dev->maj, dev->min);
|
||||||
* 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;
|
|
||||||
|
|
||||||
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 */
|
/* Try mnt_table_find_srcpath() which also cannonicalize patchs, etc.
|
||||||
fsroot = mnt_fs_get_root(fs);
|
*/
|
||||||
if (fsroot && strcmp(fsroot, "/") != 0) {
|
if (!dev->nfss) {
|
||||||
/* hmm.. we found bind mount or btrfs subvolume, let's try to
|
fs = get_active_swap(dev->filename);
|
||||||
* get real FS root mountpoint */
|
if (!fs) {
|
||||||
struct libmnt_fs *rfs;
|
fs = mnt_table_find_srcpath(mtab, dev->filename, MNT_ITER_BACKWARD);
|
||||||
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
if (fs)
|
||||||
|
dev->is_swap = 1;
|
||||||
|
}
|
||||||
|
if (fs)
|
||||||
|
add_filesystem(dev, fs);
|
||||||
|
}
|
||||||
|
|
||||||
mnt_table_set_iter(mtab, itr, fs);
|
done:
|
||||||
while (mnt_table_next_fs(mtab, itr, &rfs) == 0) {
|
mnt_free_iter(itr);
|
||||||
fsroot = mnt_fs_get_root(rfs);
|
if (n)
|
||||||
if ((!fsroot || strcmp(fsroot, "/") == 0)
|
*n = dev->nfss;
|
||||||
&& mnt_fs_match_source(rfs, dev->filename, mntcache)) {
|
return dev->fss;
|
||||||
fs = rfs;
|
}
|
||||||
|
|
||||||
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mnt_free_iter(itr);
|
|
||||||
}
|
}
|
||||||
|
if (mnt_fs_is_swaparea(fs))
|
||||||
DBG(DEV, ul_debugobj(dev, "mountpoint: %s", mnt_fs_get_target(fs)));
|
return "[SWAP]";
|
||||||
dev->mountpoint = xstrdup(mnt_fs_get_target(fs));
|
return mnt_fs_get_target(fs);
|
||||||
dev->is_mounted = 1;
|
|
||||||
return dev->mountpoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lsblk_mnt_init(void)
|
void lsblk_mnt_init(void)
|
||||||
|
|
|
@ -46,6 +46,15 @@ case it is recommended to use
|
||||||
before
|
before
|
||||||
.B lsblk
|
.B lsblk
|
||||||
to synchronize with udev.
|
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
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.BR \-a , " \-\-all"
|
.BR \-a , " \-\-all"
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "optutils.h"
|
#include "optutils.h"
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "loopdev.h"
|
#include "loopdev.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
#include "lsblk.h"
|
#include "lsblk.h"
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ enum {
|
||||||
COL_FSUSEPERC,
|
COL_FSUSEPERC,
|
||||||
COL_FSVERSION,
|
COL_FSVERSION,
|
||||||
COL_TARGET,
|
COL_TARGET,
|
||||||
|
COL_TARGETS,
|
||||||
COL_LABEL,
|
COL_LABEL,
|
||||||
COL_UUID,
|
COL_UUID,
|
||||||
COL_PTUUID,
|
COL_PTUUID,
|
||||||
|
@ -164,7 +166,9 @@ static struct colinfo infos[] = {
|
||||||
[COL_FSUSEPERC] = { "FSUSE%", 3, SCOLS_FL_RIGHT, N_("filesystem use percentage") },
|
[COL_FSUSEPERC] = { "FSUSE%", 3, SCOLS_FL_RIGHT, N_("filesystem use percentage") },
|
||||||
[COL_FSVERSION] = { "FSVER", 0.1, SCOLS_FL_TRUNC, N_("filesystem version") },
|
[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_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_LABEL] = { "LABEL", 0.1, 0, N_("filesystem LABEL") },
|
||||||
[COL_UUID] = { "UUID", 36, 0, N_("filesystem UUID") },
|
[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;
|
char *sizestr;
|
||||||
uint64_t vfs_attr = 0;
|
uint64_t vfs_attr = 0;
|
||||||
char *mnt;
|
|
||||||
|
|
||||||
if (!dev->fsstat.f_blocks) {
|
if (!dev->fsstat.f_blocks) {
|
||||||
mnt = lsblk_device_get_mountpoint(dev);
|
const char *mnt = lsblk_device_get_mountpoint(dev);
|
||||||
if (!mnt || dev->is_swap)
|
if (!mnt || dev->is_swap)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (statvfs(mnt, &dev->fsstat) != 0)
|
if (statvfs(mnt, &dev->fsstat) != 0)
|
||||||
|
@ -799,11 +802,27 @@ static char *device_get_data(
|
||||||
break;
|
break;
|
||||||
case COL_TARGET:
|
case COL_TARGET:
|
||||||
{
|
{
|
||||||
char *s = lsblk_device_get_mountpoint(dev);
|
const char *p = lsblk_device_get_mountpoint(dev);
|
||||||
if (s)
|
if (p)
|
||||||
str = xstrdup(s);
|
str = xstrdup(p);
|
||||||
else
|
break;
|
||||||
str = NULL;
|
}
|
||||||
|
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
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case COL_LABEL:
|
case COL_LABEL:
|
||||||
|
@ -2182,6 +2201,15 @@ int main(int argc, char *argv[])
|
||||||
ci->type == COLTYPE_SORTNUM ? cmp_u64_cells : scols_cmpstr_cells,
|
ci->type == COLTYPE_SORTNUM ? cmp_u64_cells : scols_cmpstr_cells,
|
||||||
NULL);
|
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) {
|
if (lsblk->flags & LSBLK_JSON) {
|
||||||
switch (ci->type) {
|
switch (ci->type) {
|
||||||
case COLTYPE_SIZE:
|
case COLTYPE_SIZE:
|
||||||
|
@ -2189,13 +2217,16 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case COLTYPE_NUM:
|
case COLTYPE_NUM:
|
||||||
scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
|
scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
|
||||||
break;
|
break;
|
||||||
case COLTYPE_BOOL:
|
case COLTYPE_BOOL:
|
||||||
scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN);
|
scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
#include <libsmartcols.h>
|
#include <libsmartcols.h>
|
||||||
|
#include <libmount.h>
|
||||||
|
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
@ -33,7 +34,6 @@ UL_DEBUG_DECLARE_MASK(lsblk);
|
||||||
|
|
||||||
struct lsblk {
|
struct lsblk {
|
||||||
struct libscols_table *table; /* output table */
|
struct libscols_table *table; /* output table */
|
||||||
|
|
||||||
struct libscols_column *sort_col;/* sort output by this column */
|
struct libscols_column *sort_col;/* sort output by this column */
|
||||||
|
|
||||||
int sort_id; /* id of the sort column */
|
int sort_id; /* id of the sort column */
|
||||||
|
@ -117,7 +117,9 @@ struct lsblk_device {
|
||||||
|
|
||||||
struct path_cxt *sysfs;
|
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 */
|
struct statvfs fsstat; /* statvfs() result */
|
||||||
|
|
||||||
int npartitions; /* # of partitions this device has */
|
int npartitions; /* # of partitions this device has */
|
||||||
|
@ -207,7 +209,9 @@ struct lsblk_iter {
|
||||||
extern void lsblk_mnt_init(void);
|
extern void lsblk_mnt_init(void);
|
||||||
extern void lsblk_mnt_deinit(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 */
|
/* lsblk-properties.c */
|
||||||
extern void lsblk_device_free_properties(struct lsblk_devprop *p);
|
extern void lsblk_device_free_properties(struct lsblk_devprop *p);
|
||||||
|
|
Loading…
Reference in New Issue