summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tt.h2
-rw-r--r--lib/tt.c8
-rw-r--r--misc-utils/findmnt.810
-rw-r--r--misc-utils/findmnt.c104
4 files changed, 91 insertions, 33 deletions
diff --git a/include/tt.h b/include/tt.h
index e6a63ed3..b27f51ea 100644
--- a/include/tt.h
+++ b/include/tt.h
@@ -47,6 +47,7 @@ struct tt_column {
struct tt_line {
struct tt *table;
char const **data;
+ void *userdata;
struct list_head ln_lines; /* table lines */
@@ -68,6 +69,7 @@ extern struct tt_column *tt_get_column(struct tt *tb, int colnum);
extern struct tt_line *tt_add_line(struct tt *tb, struct tt_line *parent);
extern int tt_line_set_data(struct tt_line *ln, int colnum, const char *data);
+extern int tt_line_set_userdata(struct tt_line *ln, void *data);
extern int tt_parse_columns_list(const char *list, int cols[], int *ncols,
int (name2id)(const char *, size_t));
diff --git a/lib/tt.c b/lib/tt.c
index 1043ee32..ffa5897d 100644
--- a/lib/tt.c
+++ b/lib/tt.c
@@ -304,6 +304,14 @@ static int get_terminal_width(void)
return 0;
}
+int tt_line_set_userdata(struct tt_line *ln, void *data)
+{
+ if (!ln)
+ return -1;
+ ln->userdata = data;
+ return 0;
+}
+
static char *line_get_ascii_art(struct tt_line *ln, char *buf, size_t *bufsz)
{
const char *art;
diff --git a/misc-utils/findmnt.8 b/misc-utils/findmnt.8
index 2f9dd74a..8c4f2bef 100644
--- a/misc-utils/findmnt.8
+++ b/misc-utils/findmnt.8
@@ -64,7 +64,9 @@ Print the first matching filesystem only.
.IP "\fB\-i, \-\-invert\fP"
Invert the sense of matching.
.IP "\fB\-l, \-\-list\fP"
-Use the list output format.
+Use the list output format. This output format is automatically enabled if the
+output is restricted by \fB\-t\fP, \fB\-O\fP, \fB\-S\fP or \fB\-T\fP
+option and the option \fB\-\-submounts\fP is not used.
.IP "\fB\-v, \-\-nofsroot\fP"
Do not print a [/dir] in the SOURCE column for bind-mounts or btrfs subvolumes.
.IP "\fB\-n, \-\-noheadings\fP"
@@ -120,6 +122,12 @@ prefixed with
to specify the filesystem types on which no action should be taken. For
more details see
.BR mount (8).
+.IP "\fB\-R, \-\-submounts\fP"
+Print recursively all submounts for the selected filesystems. The restictions
+defined by options \fB\-t\fP, \fB\-O\fP, \fB\-S\fP, \fB\-T\fP and
+\fB\--direction\fP are not applied to submounts. All submounts are always
+printed in tree-like order. The option enables the tree-like output format by
+default. This option has no effect for \fB\-\-mtab\fP or \fB\-\-fstab\fP.
.IP "\fB\-S, \-\-source \fIspec\fP"
Explicitly define the mount source. Supported are device, LABEL= or UUID=.
.IP "\fB\-T, \-\-target \fIdir\fP"
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
index 4b9d45ba..af5d6e04 100644
--- a/misc-utils/findmnt.c
+++ b/misc-utils/findmnt.c
@@ -47,6 +47,7 @@ enum {
FL_INVERT = (1 << 4),
FL_NOSWAPMATCH = (1 << 6),
FL_NOFSROOT = (1 << 7),
+ FL_SUBMOUNTS = (1 << 8),
};
/* column IDs */
@@ -297,10 +298,23 @@ static struct tt_line *add_line(struct tt *tt, mnt_fs *fs,
for (i = 0; i < ncolumns; i++)
tt_line_set_data(line, i, get_data(fs, i));
+ tt_line_set_userdata(line, fs);
return line;
}
-/* reads filesystems from @tb (libmount) and fillin @tab (output table) */
+static int has_line(struct tt *tt, mnt_fs *fs)
+{
+ struct list_head *p;
+
+ list_for_each(p, &tt->tb_lines) {
+ struct tt_line *ln = list_entry(p, struct tt_line, ln_lines);
+ if ((mnt_fs *) ln->userdata == fs)
+ return 1;
+ }
+ return 0;
+}
+
+/* reads filesystems from @tb (libmount) and fillin @tt (output table) */
static int create_treenode(struct tt *tt, mnt_tab *tb,
mnt_fs *fs, struct tt_line *parent_line)
{
@@ -314,7 +328,9 @@ static int create_treenode(struct tt *tt, mnt_tab *tb,
if (mnt_tab_get_root_fs(tb, &fs))
goto leave;
parent_line = NULL;
- }
+
+ } else if ((flags & FL_SUBMOUNTS) && has_line(tt, fs))
+ return 0;
itr = mnt_new_iter(MNT_ITER_FORWARD);
if (!itr)
@@ -446,6 +462,38 @@ again:
return fs;
}
+static int add_matching_lines(mnt_tab *tb, struct tt *tt, int direction)
+{
+ mnt_iter *itr = NULL;
+ mnt_fs *fs;
+ int nlines = 0, rc = -1;
+
+ itr = mnt_new_iter(direction);
+ if (!itr) {
+ warn(_("failed to initialize libmount iterator"));
+ goto done;
+ }
+
+ while((fs = get_next_fs(tb, itr))) {
+ if ((tt_flags & TT_FL_TREE) || (flags & FL_SUBMOUNTS))
+ rc = create_treenode(tt, tb, fs, NULL);
+ else
+ rc = !add_line(tt, fs, NULL);
+ if (rc)
+ goto done;
+ nlines++;
+ if (flags & FL_FIRSTONLY)
+ break;
+ flags |= FL_NOSWAPMATCH;
+ }
+
+ if (nlines)
+ rc = 0;
+done:
+ mnt_free_iter(itr);
+ return rc;
+}
+
static void __attribute__((__noreturn__)) usage(FILE *out)
{
int i;
@@ -480,6 +528,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
" -a, --ascii use ascii chars for tree formatting\n"
" -t, --types <list> limit the set of filesystem by FS types\n"
" -v, --nofsroot don't print [/dir] for bind or btrfs mounts\n"
+ " -R, --submounts print all submount for the matching filesystems\n"
" -S, --source <string> device, LABEL= or UUID=device\n"
" -T, --target <string> mountpoint\n\n"));
@@ -509,16 +558,13 @@ int main(int argc, char *argv[])
{
/* libmount */
mnt_tab *tb = NULL;
- mnt_iter *itr = NULL;
- mnt_fs *fs = NULL;
char *tabfile = NULL;
int direction = MNT_ITER_FORWARD;
+ int i, c, rc = -1;
/* table.h */
struct tt *tt = NULL;
- int i, c, nlines = 0, rc = EXIT_FAILURE;
-
struct option longopts[] = {
{ "ascii", 0, 0, 'a' },
{ "canonicalize", 0, 0, 'c' },
@@ -538,6 +584,7 @@ int main(int argc, char *argv[])
{ "raw", 0, 0, 'r' },
{ "types", 1, 0, 't' },
{ "fsroot", 0, 0, 'v' },
+ { "submounts", 0, 0, 'R' },
{ "source", 1, 0, 'S' },
{ "target", 1, 0, 'T' },
@@ -560,7 +607,7 @@ int main(int argc, char *argv[])
tt_flags |= TT_FL_TREE;
while ((c = getopt_long(argc, argv,
- "acd:ehifo:O:klmnrst:uvS:T:", longopts, NULL)) != -1) {
+ "acd:ehifo:O:klmnrst:uvRS:T:", longopts, NULL)) != -1) {
switch(c) {
case 'a':
tt_flags |= TT_FL_ASCII;
@@ -636,6 +683,9 @@ int main(int argc, char *argv[])
case 'v':
flags |= FL_NOFSROOT;
break;
+ case 'R':
+ flags |= FL_SUBMOUNTS;
+ break;
case 'S':
set_match(COL_SOURCE, optarg);
flags |= FL_NOSWAPMATCH;
@@ -669,7 +719,12 @@ int main(int argc, char *argv[])
if (optind < argc)
set_match(COL_TARGET, argv[optind++]); /* mountpoint */
- if (!is_listall_mode() || (flags & FL_FIRSTONLY))
+ if ((flags & FL_SUBMOUNTS) && is_listall_mode())
+ /* don't care about submounts if list all mounts */
+ flags &= ~FL_SUBMOUNTS;
+
+ if (!(flags & FL_SUBMOUNTS) &&
+ (!is_listall_mode() || (flags & FL_FIRSTONLY)))
tt_flags &= ~TT_FL_TREE;
if (!(flags & FL_NOSWAPMATCH) &&
@@ -693,12 +748,6 @@ int main(int argc, char *argv[])
if (!tb)
goto leave;
- itr = mnt_new_iter(direction);
- if (!itr) {
- warn(_("failed to initialize libmount iterator"));
- goto leave;
- }
-
cache = mnt_new_cache();
if (!cache) {
warn(_("failed to initialize libmount cache"));
@@ -731,32 +780,23 @@ int main(int argc, char *argv[])
/*
* Fill in data to the output table
*/
- if (tt_flags & TT_FL_TREE) {
- if (create_treenode(tt, tb, NULL, NULL))
- goto leave;
- } else {
- while((fs = get_next_fs(tb, itr))) {
- if (!add_line(tt, fs, NULL))
- goto leave;
- nlines++;
- if (flags & FL_FIRSTONLY)
- break;
- }
- }
+ if ((tt_flags & TT_FL_TREE) && is_listall_mode())
+ /* whole tree */
+ rc = create_treenode(tt, tb, NULL, NULL);
+ else
+ /* whole lits of sub-tree */
+ rc = add_matching_lines(tb, tt, direction);
/*
* Print the output table
*/
- tt_print_table(tt);
-
- if (is_listall_mode() || nlines)
- rc = EXIT_SUCCESS;
+ if (!rc)
+ tt_print_table(tt);
leave:
tt_free_table(tt);
mnt_free_tab(tb);
mnt_free_cache(cache);
- mnt_free_iter(itr);
- return rc;
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}