summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--misc-utils/Makemodule.am4
-rw-r--r--misc-utils/findmnt-verify.c201
-rw-r--r--misc-utils/findmnt.c81
-rw-r--r--misc-utils/findmnt.h39
-rw-r--r--sys-utils/fstab.52
5 files changed, 284 insertions, 43 deletions
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index 120aadf24..a240eab66 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -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
index 000000000..46897da96
--- /dev/null
+++ b/misc-utils/findmnt-verify.c
@@ -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;
+}
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
index b2ff04e8f..ea4d23d8e 100644
--- a/misc-utils/findmnt.c
+++ b/misc-utils/findmnt.c
@@ -47,31 +47,7 @@
#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
index 000000000..fbaa38e82
--- /dev/null
+++ b/misc-utils/findmnt.h
@@ -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 */
diff --git a/sys-utils/fstab.5 b/sys-utils/fstab.5
index 2f20fed06..bd9ce2e71 100644
--- a/sys-utils/fstab.5
+++ b/sys-utils/fstab.5
@@ -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