]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
findmnt: add --verify and --verbose
authorKarel Zak <kzak@redhat.com>
Tue, 20 Sep 2016 13:45:15 +0000 (15:45 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 23 Sep 2016 11:21:02 +0000 (13:21 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/Makemodule.am
misc-utils/findmnt-verify.c [new file with mode: 0644]
misc-utils/findmnt.c
misc-utils/findmnt.h [new file with mode: 0644]
sys-utils/fstab.5

index 120aadf2427d8529fe419131bc03bf5821577d25..a240eab66b506bd4f005ec0416fbedbc718fb31a 100644 (file)
@@ -143,7 +143,9 @@ bin_PROGRAMS += findmnt
 dist_man_MANS += misc-utils/findmnt.8
 findmnt_LDADD = $(LDADD) libmount.la libcommon.la libsmartcols.la
 findmnt_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir) -I$(ul_libsmartcols_incdir)
-findmnt_SOURCES = misc-utils/findmnt.c
+findmnt_SOURCES = misc-utils/findmnt.c \
+                 misc-utils/findmnt-verify.c \
+                 misc-utils/findmnt.h
 if HAVE_UDEV
 findmnt_LDADD += -ludev
 endif
diff --git a/misc-utils/findmnt-verify.c b/misc-utils/findmnt-verify.c
new file mode 100644 (file)
index 0000000..46897da
--- /dev/null
@@ -0,0 +1,201 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libmount.h>
+
+#include "nls.h"
+#include "c.h"
+#include "strutils.h"
+#include "xalloc.h"
+
+#include "findmnt.h"
+
+struct verify_context {
+       struct libmnt_fs        *fs;
+       struct libmnt_table     *tb;
+
+       int     nwarnings;
+       int     nerrors;
+
+       unsigned int    target_printed : 1;
+};
+
+static void verify_mesg(struct verify_context *vfy, char type, const char *fmt, va_list ap)
+{
+       if (!vfy->target_printed)
+               fprintf(stdout, "%s\n", mnt_fs_get_target(vfy->fs));
+
+       fprintf(stdout, "   [%c] ", type);
+       vfprintf(stdout, fmt, ap);
+       fputc('\n', stdout);
+}
+
+static int verify_warn(struct verify_context *vfy, const char *fmt, ...)
+{
+       va_list ap;
+       vfy->nwarnings++;
+       va_start(ap, fmt);
+       verify_mesg(vfy, 'W', fmt, ap);
+       va_end(ap);
+       return 0;
+}
+
+static int verify_err(struct verify_context *vfy, const char *fmt, ...)
+{
+       va_list ap;
+       vfy->nerrors++;
+       va_start(ap, fmt);
+       verify_mesg(vfy, 'E', fmt, ap);
+       va_end(ap);
+       return 0;
+}
+
+static int verify_ok(struct verify_context *vfy __attribute__((unused)),
+                     const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!(flags & FL_VERBOSE))
+               return 0;
+
+       va_start(ap, fmt);
+       verify_mesg(vfy, '+', fmt, ap);
+       va_end(ap);
+       return 0;
+}
+
+static int verify_order(struct verify_context *vfy)
+{
+       struct libmnt_iter *itr = NULL;
+       struct libmnt_fs *next;
+       const char *tgt;
+
+       tgt = mnt_fs_get_target(vfy->fs);
+       if (tgt && !(flags & FL_NOCACHE))
+               tgt  = mnt_resolve_target(tgt, cache);
+       else if (!tgt)
+               return 0;
+
+       itr = mnt_new_iter(MNT_ITER_FORWARD);
+       if (!itr) {
+               warn(_("failed to initialize libmount iterator"));
+               goto done;
+       }
+
+       /* set iterator position to 'fs' */
+       mnt_table_set_iter(vfy->tb, itr, vfy->fs);
+       mnt_table_next_fs(vfy->tb, itr, &next);
+
+       /* scan all next filesystems */
+       while (mnt_table_next_fs(vfy->tb, itr, &next) == 0) {
+               const char *n_tgt;
+               size_t len;
+
+               n_tgt = mnt_fs_get_target(next);
+               if (n_tgt && !(flags & FL_NOCACHE))
+                       n_tgt  = mnt_resolve_target(n_tgt, cache);
+               else if (!n_tgt)
+                       continue;
+               len = strlen(n_tgt);
+
+               if (strncmp(n_tgt, tgt, len) == 0) {
+                       if (*(tgt + len) == '\0')
+                               verify_warn(vfy, _("target specified more than once"));
+                       else if (*(tgt + len) == '/')
+                               verify_err(vfy, _("wrong order: %s specified before %s"), tgt, n_tgt);
+               }
+       }
+done:
+       mnt_free_iter(itr);
+       return 0;
+}
+
+static int verify_target(struct verify_context *vfy)
+{
+       const char *tgt = mnt_fs_get_target(vfy->fs);
+       const char *cn = tgt;
+       struct stat sb;
+
+       if (!tgt)
+               return verify_err(vfy, _("undefined target (mountpoint)"));
+
+       if (!(flags & FL_NOCACHE)) {
+               cn = mnt_resolve_target(tgt, cache);
+               if (!cn)
+                       return -ENOMEM;
+               if (strcmp(cn, tgt) != 0)
+                       verify_warn(vfy, _("non-canonical target path (real: %s)"), cn);
+               tgt = cn;
+       }
+       if (stat(tgt, &sb) != 0) {
+               if (mnt_fs_get_option(vfy->fs, "noauto", NULL, NULL) == 1)
+                       verify_err(vfy, _("on boot required target unaccessible: %m"));
+               else
+                       verify_warn(vfy, _("target unaccessible: %m"));
+
+       } else if (!S_ISDIR(sb.st_mode)
+                && mnt_fs_get_option(vfy->fs, "bind", NULL, NULL) == 1) {
+               verify_err(vfy, _("target is not a directory"));
+       } else
+               verify_ok(vfy, _("target accessible"));
+
+       return 0;
+}
+
+static int verify_filesystem(struct verify_context *vfy)
+{
+       int rc = 0;
+
+       if (!mnt_fs_is_swaparea(vfy->fs))
+               rc = verify_target(vfy);
+       return rc;
+}
+
+int verify_table(struct libmnt_table *tb)
+{
+       struct verify_context vfy = { .nerrors = 0 };
+       struct libmnt_iter *itr = NULL;
+       int rc = 0;             /* overall return code (alloc errors, etc.) */
+       int check_order = is_listall_mode();
+
+       itr = mnt_new_iter(MNT_ITER_FORWARD);
+       if (!itr) {
+               warn(_("failed to initialize libmount iterator"));
+               goto done;
+       }
+
+       vfy.tb = tb;
+
+       while (rc == 0 && (vfy.fs = get_next_fs(tb, itr))) {
+               vfy.target_printed = 0;
+               if (check_order)
+                       rc = verify_order(&vfy);
+               if (!rc)
+                       rc = verify_filesystem(&vfy);
+
+               if (flags & FL_FIRSTONLY)
+                       break;
+               flags |= FL_NOSWAPMATCH;
+       }
+
+done:
+       mnt_free_iter(itr);
+
+       /* summary */
+       if (vfy.nerrors || parse_nerrors || vfy.nwarnings) {
+               fputc('\n', stderr);
+               fprintf(stderr, P_("%d parse error", "%d parse errors", parse_nerrors), parse_nerrors);
+               fprintf(stderr, P_(", %d error",     ", %d errors", vfy.nerrors), vfy.nerrors);
+               fprintf(stderr, P_(", %d warning",   ", %d warnings", vfy.nwarnings), vfy.nwarnings);
+               fputc('\n', stderr);
+       } else
+               fprintf(stdout, _("\nSuccess, no errors or warnings detected\n"));
+
+       return rc != 0 ? rc : vfy.nerrors + parse_nerrors;
+}
index b2ff04e8f270216fb6368c56ca10d594b2a12c97..ea4d23d8e18971a577278f63d656ecd9c62f2c8e 100644 (file)
 #include "optutils.h"
 #include "mangle.h"
 
-/* flags */
-enum {
-       FL_EVALUATE     = (1 << 1),
-       FL_CANONICALIZE = (1 << 2),
-       FL_FIRSTONLY    = (1 << 3),
-       FL_INVERT       = (1 << 4),
-       FL_NOSWAPMATCH  = (1 << 6),
-       FL_NOFSROOT     = (1 << 7),
-       FL_SUBMOUNTS    = (1 << 8),
-       FL_POLL         = (1 << 9),
-       FL_DF           = (1 << 10),
-       FL_ALL          = (1 << 11),
-       FL_UNIQ         = (1 << 12),
-       FL_BYTES        = (1 << 13),
-       FL_NOCACHE      = (1 << 14),
-       FL_STRICTTARGET = (1 << 15),
-
-       /* basic table settings */
-       FL_ASCII        = (1 << 20),
-       FL_RAW          = (1 << 21),
-       FL_NOHEADINGS   = (1 << 22),
-       FL_EXPORT       = (1 << 23),
-       FL_TREE         = (1 << 24),
-       FL_JSON         = (1 << 25),
-};
+#include "findmnt.h"
 
 /* column IDs */
 enum {
@@ -166,17 +142,16 @@ static inline size_t err_columns_index(size_t arysz, size_t idx)
 #define add_column(ary, n, id) \
                ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id))
 
-/* global flags */
-static int flags;
-
-
 /* poll actions (parsed --poll=<list> */
 #define FINDMNT_NACTIONS       4               /* mount, umount, move, remount */
 static int actions[FINDMNT_NACTIONS];
 static int nactions;
 
-/* libmount cache */
-static struct libmnt_cache *cache;
+/* global (accessed from findmnt-verify.c too) */
+int flags;
+int parse_nerrors;
+struct libmnt_cache *cache;
+
 
 #ifdef HAVE_LIBUDEV
 struct udev *udev;
@@ -315,7 +290,7 @@ static int is_tabdiff_column(int id)
 /*
  * "findmnt" without any filter
  */
-static int is_listall_mode(void)
+int is_listall_mode(void)
 {
        if ((flags & FL_DF) && !(flags & FL_ALL))
                return 0;
@@ -805,6 +780,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
                        const char *filename, int line)
 {
        warnx(_("%s: parse error at line %d -- ignored"), filename, line);
+       ++parse_nerrors;
        return 1;
 }
 
@@ -973,7 +949,7 @@ static int match_func(struct libmnt_fs *fs,
 }
 
 /* iterate over filesystems in @tb */
-static struct libmnt_fs *get_next_fs(struct libmnt_table *tb,
+struct libmnt_fs *get_next_fs(struct libmnt_table *tb,
                                     struct libmnt_iter *itr)
 {
        struct libmnt_fs *fs = NULL;
@@ -1254,7 +1230,12 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
        fputs(_(" -t, --types <list>     limit the set of filesystems by FS types\n"), out);
        fputs(_(" -U, --uniq             ignore filesystems with duplicate target\n"), out);
        fputs(_(" -u, --notruncate       don't truncate text in columns\n"), out);
-       fputs(_(" -v, --nofsroot         don't print [/dir] for bind or btrfs mounts\n"), out);
+       fputs(_(" -v, --nofsroot         don't print [/dir] for bind or btrfs mounts\n"), out); 
+
+       fputc('\n', out);
+       fputs(_(" -x, --verify           verify mount table content (default is fstab)\n"), out);
+       fputs(_("     --verbose          print more details\n"), out);
+       fputc('\n', out);
 
        fputs(USAGE_SEPARATOR, out);
        fputs(USAGE_HELP, out);
@@ -1275,6 +1256,7 @@ int main(int argc, char *argv[])
        struct libmnt_table *tb = NULL;
        char **tabfiles = NULL;
        int direction = MNT_ITER_FORWARD;
+       int verify = 0;
        int c, rc = -1, timeout = -1;
        int ntabfiles = 0, tabtype = 0;
        char *outarg = NULL;
@@ -1282,6 +1264,10 @@ int main(int argc, char *argv[])
 
        struct libscols_table *table = NULL;
 
+       enum {
+                FINDMNT_OPT_VERBOSE = CHAR_MAX + 1
+       };
+
        static const struct option longopts[] = {
            { "all",          0, 0, 'A' },
            { "ascii",        0, 0, 'a' },
@@ -1316,18 +1302,20 @@ int main(int argc, char *argv[])
            { "target",       1, 0, 'T' },
            { "timeout",      1, 0, 'w' },
            { "uniq",         0, 0, 'U' },
+           { "verify",       0, 0, 'x' },
            { "version",      0, 0, 'V' },
-
+           { "verbose",      0, 0, FINDMNT_OPT_VERBOSE },
            { NULL,           0, 0, 0 }
        };
 
        static const ul_excl_t excl[] = {       /* rows and cols in in ASCII order */
                { 'C', 'c'},                    /* [no]canonicalize */
                { 'C', 'e' },                   /* nocanonicalize, evaluate */
-               { 'J', 'P', 'r' },              /* json,pairs,raw */
+               { 'J', 'P', 'r','x' },          /* json,pairs,raw,verify */
                { 'M', 'T' },                   /* mountpoint, target */
                { 'N','k','m','s' },            /* task,kernel,mtab,fstab */
-               { 'P','l','r' },                /* pairs,list,raw */
+               { 'P','l','r','x' },            /* pairs,list,raw,verify */
+               { 'p','x' },                    /* poll,verify */
                { 'm','p','s' },                /* mtab,poll,fstab */
                { 0 }
        };
@@ -1342,7 +1330,7 @@ int main(int argc, char *argv[])
        flags |= FL_TREE;
 
        while ((c = getopt_long(argc, argv,
-                               "AabCcDd:ehiJfF:o:O:p::PklmM:nN:rst:uvRS:T:Uw:V",
+                               "AabCcDd:ehiJfF:o:O:p::PklmM:nN:rst:uvRS:T:Uw:Vx",
                                longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
@@ -1474,6 +1462,12 @@ int main(int argc, char *argv[])
                case 'V':
                        printf(UTIL_LINUX_VERSION);
                        return EXIT_SUCCESS;
+               case 'x':
+                       verify = 1;
+                       break;
+               case FINDMNT_OPT_VERBOSE:
+                       flags |= FL_VERBOSE;
+                       break;
                default:
                        usage(stderr);
                        break;
@@ -1506,7 +1500,7 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
 
        if (!tabtype)
-               tabtype = TABTYPE_KERNEL;
+               tabtype = verify ? TABTYPE_FSTAB : TABTYPE_KERNEL;
 
        if ((flags & FL_POLL) && ntabfiles > 1)
                errx(EXIT_FAILURE, _("--poll accepts only one file, but more specified by --tab-file"));
@@ -1548,7 +1542,6 @@ int main(int argc, char *argv[])
         * initialize libmount
         */
        mnt_init_debug(0);
-       scols_init_debug(0);
 
        tb = parse_tabfiles(tabfiles, ntabfiles, tabtype);
        if (!tb)
@@ -1575,9 +1568,15 @@ int main(int argc, char *argv[])
        if (flags & FL_UNIQ)
                mnt_table_uniq_fs(tb, MNT_UNIQ_KEEPTREE, uniq_fs_target_cmp);
 
+       if (verify) {
+               rc = verify_table(tb);
+               goto leave;
+       }
+
        /*
-        * initialize output formatting (libsmartcols.h)
+        * initialize libsmartcols
         */
+       scols_init_debug(0);
        table = scols_new_table();
        if (!table) {
                warn(_("failed to initialize output table"));
diff --git a/misc-utils/findmnt.h b/misc-utils/findmnt.h
new file mode 100644 (file)
index 0000000..fbaa38e
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef UTIL_LINUX_FINDMNT_H
+#define UTIL_LINUX_FINDMNT_H
+
+/* flags */
+enum {
+       FL_EVALUATE     = (1 << 1),
+       FL_CANONICALIZE = (1 << 2),
+       FL_FIRSTONLY    = (1 << 3),
+       FL_INVERT       = (1 << 4),
+       FL_NOSWAPMATCH  = (1 << 6),
+       FL_NOFSROOT     = (1 << 7),
+       FL_SUBMOUNTS    = (1 << 8),
+       FL_POLL         = (1 << 9),
+       FL_DF           = (1 << 10),
+       FL_ALL          = (1 << 11),
+       FL_UNIQ         = (1 << 12),
+       FL_BYTES        = (1 << 13),
+       FL_NOCACHE      = (1 << 14),
+       FL_STRICTTARGET = (1 << 15),
+       FL_VERBOSE      = (1 << 16),
+
+       /* basic table settings */
+       FL_ASCII        = (1 << 20),
+       FL_RAW          = (1 << 21),
+       FL_NOHEADINGS   = (1 << 22),
+       FL_EXPORT       = (1 << 23),
+       FL_TREE         = (1 << 24),
+       FL_JSON         = (1 << 25),
+};
+
+extern struct libmnt_cache *cache;
+extern int flags;
+extern int parse_nerrors;
+
+extern int is_listall_mode(void);
+extern struct libmnt_fs *get_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr);
+extern int verify_table(struct libmnt_table *tb);
+
+#endif /* UTIL_LINUX_FINDMNT_H */
index 2f20fed06ee4fd916ba4ddfd7875a1a571032563..bd9ce2e71eaaf8785d8474bb221cbfbb9aa9352a 100644 (file)
@@ -114,7 +114,7 @@ lower case characters.
 .B The second field
 .RI ( fs_file ).
 .RS
-This field describes the mount point for the filesystem.  For swap partitions, this
+This field describes the mount point (target) for the filesystem.  For swap partitions, this
 field should be specified as `none'. If the name of the mount point
 contains spaces these can be escaped as `\\040'.
 .RE