From 049caefdcf5f0fa01339fcca012ea23b7b147619 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 4 Jan 2011 14:01:33 +0100 Subject: [PATCH] findmnt: add --submounts option Signed-off-by: Karel Zak --- include/tt.h | 2 + lib/tt.c | 8 ++++ misc-utils/findmnt.8 | 10 ++++- misc-utils/findmnt.c | 104 ++++++++++++++++++++++++++++++------------- 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 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 device, LABEL= or UUID=device\n" " -T, --target 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; } -- 2.39.5