findmnt: add --verify and --verbose

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2016-09-20 15:45:15 +02:00
parent e0140aa138
commit c768892f4c
5 changed files with 284 additions and 43 deletions

View 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

201
misc-utils/findmnt-verify.c Normal file
View File

@ -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;
}

View File

@ -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"));

39
misc-utils/findmnt.h Normal file
View File

@ -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 */

View 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