diff options
author | Karel Zak | 2011-04-27 17:19:04 +0200 |
---|---|---|
committer | Karel Zak | 2011-04-27 17:19:04 +0200 |
commit | 32e5466aa79fedaebf6e101fbfe22c0705805af9 (patch) | |
tree | 8dfbed72092ee5b0cc6eeeb83ee9ad2aec35c62b /misc-utils/findmnt.c | |
parent | libmount: minor fix to mnt_tabdiff_* (diff) | |
download | kernel-qcow2-util-linux-32e5466aa79fedaebf6e101fbfe22c0705805af9.tar.gz kernel-qcow2-util-linux-32e5466aa79fedaebf6e101fbfe22c0705805af9.tar.xz kernel-qcow2-util-linux-32e5466aa79fedaebf6e101fbfe22c0705805af9.zip |
findmnt: add --poll option
The --poll functionality is based on poll(/proc/self/mountinfo) and
mnt_tabdiff_* functions from libmount.
$ findmnt --poll
ACTION TARGET SOURCE FSTYPE OPTIONS
mount /mnt/test /dev/sda1 ext3 rw,relatime,errors=continue,user_xattr,acl,barrier=0,data=ordered
... after "mount /dev/sda1 /mnt/test".
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/findmnt.c')
-rw-r--r-- | misc-utils/findmnt.c | 261 |
1 files changed, 232 insertions, 29 deletions
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c index 07c0eda27..16c26a1ce 100644 --- a/misc-utils/findmnt.c +++ b/misc-utils/findmnt.c @@ -29,6 +29,7 @@ #include <sys/ioctl.h> #endif #include <assert.h> +#include <poll.h> #define USE_UNSTABLE_LIBMOUNT_API #include <libmount.h> @@ -47,6 +48,7 @@ enum { FL_NOSWAPMATCH = (1 << 6), FL_NOFSROOT = (1 << 7), FL_SUBMOUNTS = (1 << 8), + FL_POLL = (1 << 9) }; /* column IDs */ @@ -60,6 +62,9 @@ enum { COL_LABEL, COL_UUID, COL_MAJMIN, + COL_ACTION, + COL_OLD_TARGET, + COL_OLD_OPTIONS, __NCOLUMNS }; @@ -68,21 +73,24 @@ enum { struct colinfo { const char *name; /* header */ double whint; /* width hint (N < 1 is in percent of termwidth) */ - int truncate; /* boolean */ + int flags; /* tt flags */ const char *match; /* pattern for match_func() */ }; /* columns descriptions */ struct colinfo infos[__NCOLUMNS] = { - [COL_SOURCE] = { "SOURCE", 0.25, FALSE }, - [COL_TARGET] = { "TARGET", 0.30, FALSE }, - [COL_FSTYPE] = { "FSTYPE", 0.10, TRUE }, - [COL_OPTIONS] = { "OPTIONS", 0.10, TRUE }, - [COL_VFS_OPTIONS] = { "VFS-OPTIONS", 0.20, TRUE }, - [COL_FS_OPTIONS] = { "FS-OPTIONS", 0.10, TRUE }, - [COL_LABEL] = { "LABEL", 0.10, FALSE }, - [COL_UUID] = { "UUID", 36, FALSE }, - [COL_MAJMIN] = { "MAJ:MIN", 6, FALSE }, + [COL_SOURCE] = { "SOURCE", 0.25 }, + [COL_TARGET] = { "TARGET", 0.30, TT_FL_TREE }, + [COL_FSTYPE] = { "FSTYPE", 0.10, TT_FL_TRUNC }, + [COL_OPTIONS] = { "OPTIONS", 0.10, TT_FL_TRUNC }, + [COL_VFS_OPTIONS] = { "VFS-OPTIONS", 0.20, TT_FL_TRUNC }, + [COL_FS_OPTIONS] = { "FS-OPTIONS", 0.10, TT_FL_TRUNC }, + [COL_LABEL] = { "LABEL", 0.10 }, + [COL_UUID] = { "UUID", 36 }, + [COL_MAJMIN] = { "MAJ:MIN", 6 }, + [COL_ACTION] = { "ACTION", 10, TT_FL_STRICTWIDTH }, + [COL_OLD_OPTIONS] = { "OLD-OPTIONS", 0.10, TT_FL_TRUNC }, + [COL_OLD_TARGET] = { "OLD-TARGET", 0.30 }, }; /* global flags */ @@ -124,9 +132,9 @@ static float get_column_whint(int num) return get_column_info(num)->whint; } -static int get_column_truncate(int num) +static int get_column_flags(int num) { - return get_column_info(num)->truncate; + return get_column_info(num)->flags; } static const char *get_match(int id) @@ -141,6 +149,21 @@ static void set_match(int id, const char *match) infos[id].match = match; } +static int is_tabdiff_column(int id) +{ + assert(id < __NCOLUMNS); + + switch(id) { + case COL_ACTION: + case COL_OLD_TARGET: + case COL_OLD_OPTIONS: + return 1; + default: + break; + } + return 0; +} + /* * "findmnt" without any filter */ @@ -169,12 +192,12 @@ static int is_mount_compatible_mode(void) return 1; /* ok */ } -static void set_all_columns_truncate(int set) +static void disable_columns_truncate(void) { int i; for (i = 0; i < __NCOLUMNS; i++) - infos[i].truncate = set; + infos[i].flags &= ~TT_FL_TRUNC; } /* @@ -285,6 +308,51 @@ static const char *get_data(struct libmnt_fs *fs, int num) return str; } +static const char *get_tabdiff_data(struct libmnt_fs *old_fs, + struct libmnt_fs *new_fs, + int change, + int num) +{ + const char *str = NULL; + + switch (get_column_id(num)) { + case COL_ACTION: + switch (change) { + case MNT_TABDIFF_MOUNT: + str = _("mount"); + break; + case MNT_TABDIFF_UMOUNT: + str = _("umount"); + break; + case MNT_TABDIFF_REMOUNT: + str = _("remount"); + break; + case MNT_TABDIFF_MOVE: + str = _("move"); + break; + default: + str = _("unknown"); + break; + } + break; + case COL_OLD_OPTIONS: + if (old_fs) + str = mnt_fs_get_options(old_fs); + break; + case COL_OLD_TARGET: + if (old_fs) + str = mnt_fs_get_target(old_fs); + break; + default: + if (new_fs) + str = get_data(new_fs, num); + else + str = get_data(old_fs, num); + break; + } + return str; +} + /* adds one line to the output @tab */ static struct tt_line *add_line(struct tt *tt, struct libmnt_fs *fs, struct tt_line *parent) @@ -303,6 +371,23 @@ static struct tt_line *add_line(struct tt *tt, struct libmnt_fs *fs, return line; } +static struct tt_line *add_tabdiff_line(struct tt *tt, struct libmnt_fs *new_fs, + struct libmnt_fs *old_fs, int change) +{ + int i; + struct tt_line *line = tt_add_line(tt, NULL); + + if (!line) { + warn(_("failed to add line to output")); + return NULL; + } + for (i = 0; i < ncolumns; i++) + tt_line_set_data(line, i, + get_tabdiff_data(old_fs, new_fs, change, i)); + + return line; +} + static int has_line(struct tt *tt, struct libmnt_fs *fs) { struct list_head *p; @@ -368,7 +453,7 @@ static struct libmnt_table *parse_tabfile(const char *path) struct libmnt_table *tb = mnt_new_table(); if (!tb) { - warn(_("failed to initialize libmount tab")); + warn(_("failed to initialize libmount table")); return NULL; } @@ -498,6 +583,101 @@ done: return rc; } +static int poll_table(struct libmnt_table *tb, const char *tabfile, + int timeout, struct tt *tt, int direction) +{ + FILE *f; + int rc = -1; + struct libmnt_iter *itr = NULL; + struct libmnt_table *tb_new = NULL; + struct libmnt_tabdiff *diff = NULL; + struct pollfd fds[1]; + + tb_new = mnt_new_table(); + if (!tb_new) { + warn(_("failed to initialize libmount table")); + goto done; + } + + itr = mnt_new_iter(direction); + if (!itr) { + warn(_("failed to initialize libmount iterator")); + goto done; + } + + diff = mnt_new_tabdiff(); + if (!diff) { + warn(_("failed to initialize libmount tabdiff")); + goto done; + } + + /* cache is unnecessary to detect changes */ + mnt_table_set_cache(tb, NULL); + mnt_table_set_cache(tb_new, NULL); + + f = fopen(tabfile, "r"); + if (!f) { + warn(_("%s: open failed"), tabfile); + goto done; + } + + mnt_table_set_parser_errcb(tb_new, parser_errcb); + + fds[0].fd = fileno(f); + fds[0].events = POLLPRI; + + while (1) { + struct libmnt_table *tmp; + struct libmnt_fs *old, *new; + int change, x; + + x = poll(fds, 1, timeout); + if (x == 0) + goto done; /* timeout ? */ + if (x < 0) { + warn(_("poll() failed")); + goto done; + } + + rewind(f); + rc = mnt_table_parse_stream(tb_new, f, tabfile); + if (!rc) + rc = mnt_diff_tables(diff, tb, tb_new); + if (rc < 0) + goto done; + + mnt_reset_iter(itr, direction); + while(mnt_tabdiff_next_change( + diff, itr, &old, &new, &change) == 0) { + + rc = !add_tabdiff_line(tt, new, old, change); + if (rc) + goto done; + if (flags & FL_FIRSTONLY) + break; + } + + rc = tt_print_table(tt); + if (rc) + goto done; + + /* swap tables */ + tmp = tb; + tb = tb_new; + tb_new = tmp; + + tt_remove_lines(tt); + mnt_reset_table(tb_new); + } + + rc = 0; +done: + mnt_free_table(tb_new); + mnt_free_tabdiff(diff); + mnt_free_iter(itr); + return rc; +} + static void __attribute__((__noreturn__)) usage(FILE *out) { int i; @@ -517,6 +697,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out) " -k, --kernel search in kernel table of mounted \n" " filesystems (default)\n\n" + " -p, --poll monitor changes in table of mounted filesystems\n\n" + " -c, --canonicalize canonicalize printed paths\n" " -d, --direction <word> search direction - 'forward' or 'backward'\n" " -e, --evaluate print all TAGs (LABEL/UUID) evaluated\n" @@ -585,6 +767,7 @@ int main(int argc, char *argv[]) { "notruncate", 0, 0, 'u' }, { "options", 1, 0, 'O' }, { "output", 1, 0, 'o' }, + { "poll", 0, 0, 'p' }, { "raw", 0, 0, 'r' }, { "types", 1, 0, 't' }, { "fsroot", 0, 0, 'v' }, @@ -601,17 +784,11 @@ int main(int argc, char *argv[]) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - /* default enabled columns */ - columns[ncolumns++] = COL_TARGET; - columns[ncolumns++] = COL_SOURCE; - columns[ncolumns++] = COL_FSTYPE; - columns[ncolumns++] = COL_OPTIONS; - /* default output format */ tt_flags |= TT_FL_TREE; while ((c = getopt_long(argc, argv, - "acd:ehifo:O:klmnrst:uvRS:T:", longopts, NULL)) != -1) { + "acd:ehifo:O:pklmnrst:uvRS:T:", longopts, NULL)) != -1) { switch(c) { case 'a': tt_flags |= TT_FL_ASCII; @@ -641,7 +818,7 @@ int main(int argc, char *argv[]) flags |= FL_FIRSTONLY; break; case 'u': - set_all_columns_truncate(FALSE); + disable_columns_truncate(); break; case 'o': if (tt_parse_columns_list(optarg, columns, &ncolumns, @@ -651,6 +828,10 @@ int main(int argc, char *argv[]) case 'O': set_match(COL_OPTIONS, optarg); break; + case 'p': + flags |= FL_POLL; + tt_flags &= ~TT_FL_TREE; + break; case 'm': /* mtab */ if (tabfile) errx_mutually_exclusive("--{fstab,mtab,kernel}"); @@ -704,6 +885,17 @@ int main(int argc, char *argv[]) } } + /* default columns */ + if (!ncolumns) { + if (flags & FL_POLL) + columns[ncolumns++] = COL_ACTION; + + columns[ncolumns++] = COL_TARGET; + columns[ncolumns++] = COL_SOURCE; + columns[ncolumns++] = COL_FSTYPE; + columns[ncolumns++] = COL_OPTIONS; + } + if (!tabfile) { tabfile = _PATH_PROC_MOUNTINFO; @@ -769,10 +961,17 @@ int main(int argc, char *argv[]) } for (i = 0; i < ncolumns; i++) { - int fl = get_column_truncate(i) ? TT_FL_TRUNC : 0; + int fl = get_column_flags(i); + int id = get_column_id(i); + + if (!(tt_flags & TT_FL_TREE)) + fl &= ~TT_FL_TREE; - if (get_column_id(i) == COL_TARGET && (tt_flags & TT_FL_TREE)) - fl |= TT_FL_TREE; + if (!(flags & FL_POLL) && is_tabdiff_column(id)) { + warn(_("%s column is requested, but --poll " + "is not enabled"), get_column_name(i)); + goto leave; + } if (!tt_define_column(tt, get_column_name(i), get_column_whint(i), fl)) { @@ -784,7 +983,11 @@ int main(int argc, char *argv[]) /* * Fill in data to the output table */ - if ((tt_flags & TT_FL_TREE) && is_listall_mode()) + if (flags & FL_POLL) + /* poll mode */ + poll_table(tb, tabfile, -1, tt, direction); + + else if ((tt_flags & TT_FL_TREE) && is_listall_mode()) /* whole tree */ rc = create_treenode(tt, tb, NULL, NULL); else @@ -792,9 +995,9 @@ int main(int argc, char *argv[]) rc = add_matching_lines(tb, tt, direction); /* - * Print the output table + * Print the output table for non-poll modes */ - if (!rc) + if (!rc && !(flags & FL_POLL)) tt_print_table(tt); leave: tt_free_table(tt); |