]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/findmnt-verify.c
11 #include <sys/utsname.h>
17 #include "pathnames.h"
22 struct verify_context
{
24 struct libmnt_table
*tb
;
33 unsigned int target_printed
: 1,
37 static void __attribute__ ((__format__ (__printf__
, 3, 0)))
38 verify_mesg(struct verify_context
*vfy
, char type
, const char *fmt
, va_list ap
)
40 if (!vfy
->target_printed
&& vfy
->fs
) {
41 fprintf(stdout
, "%s\n", mnt_fs_get_target(vfy
->fs
));
42 vfy
->target_printed
= 1;
45 fprintf(stdout
, " [%c] ", type
);
46 vfprintf(stdout
, fmt
, ap
);
50 static int __attribute__ ((__format__ (__printf__
, 2, 3)))
51 verify_warn(struct verify_context
*vfy
, const char *fmt
, ...)
56 verify_mesg(vfy
, 'W', fmt
, ap
);
61 static int __attribute__ ((__format__ (__printf__
, 2, 3)))
62 verify_err(struct verify_context
*vfy
, const char *fmt
, ...)
67 verify_mesg(vfy
, 'E', fmt
, ap
);
72 static int __attribute__ ((__format__ (__printf__
, 2, 3)))
73 verify_ok(struct verify_context
*vfy
__attribute__((unused
)),
78 if (!(flags
& FL_VERBOSE
))
82 verify_mesg(vfy
, ' ', fmt
, ap
);
87 static int verify_order(struct verify_context
*vfy
)
89 struct libmnt_iter
*itr
= NULL
;
90 struct libmnt_fs
*next
;
93 tgt
= mnt_fs_get_target(vfy
->fs
);
94 if (tgt
&& !(flags
& FL_NOCACHE
))
95 tgt
= mnt_resolve_target(tgt
, cache
);
99 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
101 warn(_("failed to initialize libmount iterator"));
105 /* set iterator position to 'fs' */
106 mnt_table_set_iter(vfy
->tb
, itr
, vfy
->fs
);
108 if (mnt_table_next_fs(vfy
->tb
, itr
, &next
) != 0)
111 /* scan all next filesystems */
112 while (mnt_table_next_fs(vfy
->tb
, itr
, &next
) == 0) {
116 n_tgt
= mnt_fs_get_target(next
);
117 if (n_tgt
&& !(flags
& FL_NOCACHE
))
118 n_tgt
= mnt_resolve_target(n_tgt
, cache
);
123 if (strncmp(n_tgt
, tgt
, len
) == 0) {
124 if (*(tgt
+ len
) == '\0')
125 verify_warn(vfy
, _("target specified more than once"));
126 else if (*(tgt
+ len
) == '/')
127 verify_err(vfy
, _("wrong order: %s specified before %s"), tgt
, n_tgt
);
135 static int verify_target(struct verify_context
*vfy
)
137 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
141 return verify_err(vfy
, _("undefined target (fs_file)"));
143 if (!(flags
& FL_NOCACHE
)) {
144 const char *cn
= mnt_resolve_target(tgt
, cache
);
147 if (strcmp(cn
, tgt
) != 0)
148 verify_warn(vfy
, _("non-canonical target path (real: %s)"), cn
);
151 if (stat(tgt
, &sb
) != 0) {
152 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
153 verify_err(vfy
, _("unreachable on boot required target: %m"));
155 verify_warn(vfy
, _("unreachable target: %m"));
157 } else if (!S_ISDIR(sb
.st_mode
)
158 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1) {
159 verify_err(vfy
, _("target is not a directory"));
161 verify_ok(vfy
, _("target exists"));
166 static char *verify_tag(struct verify_context
*vfy
, const char *name
,
171 if (!(flags
& FL_NOCACHE
))
172 src
= mnt_resolve_tag(name
, value
, cache
);
175 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
176 verify_err(vfy
, _("unreachable on boot required source: %s=%s"), name
, value
);
178 verify_warn(vfy
, _("unreachable: %s=%s"), name
, value
);
180 verify_ok(vfy
, _("%s=%s translated to %s"), name
, value
, src
);
185 /* Note that mount source is very FS specific and we should not
186 * interpret unreachable source as error. The exception is only
187 * NAME=value, this has to be convertible to device name.
189 static int verify_source(struct verify_context
*vfy
)
191 const char *src
= mnt_fs_get_srcpath(vfy
->fs
);
192 char *t
= NULL
, *v
= NULL
;
196 /* source is NAME=value tag */
198 const char *tag
= NULL
, *val
= NULL
;
200 if (mnt_fs_get_tag(vfy
->fs
, &tag
, &val
) != 0)
201 return verify_err(vfy
, _("undefined source (fs_spec)"));
203 src
= verify_tag(vfy
, tag
, val
);
207 /* blkid is able to parse it, but libmount does not see it as a tag --
208 * it means unsupported tag */
209 } else if (blkid_parse_tag_string(src
, &t
, &v
) == 0 && stat(src
, &sb
) != 0) {
210 rc
= verify_err(vfy
, _("unsupported source tag: %s"), src
);
213 isbind
= mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 0;
216 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
))
217 verify_ok(vfy
, _("do not check %s source (pseudo/net)"), src
);
219 else if (stat(src
, &sb
) != 0)
220 verify_warn(vfy
, _("unreachable source: %s: %m"), src
);
222 else if ((S_ISDIR(sb
.st_mode
) || S_ISREG(sb
.st_mode
)) && !isbind
)
223 verify_warn(vfy
, _("non-bind mount source %s is a directory or regular file"), src
);
225 else if (!S_ISBLK(sb
.st_mode
) && !isbind
)
226 verify_warn(vfy
, _("source %s is not a block device"), src
);
228 verify_ok(vfy
, _("source %s exists"), src
);
235 static int verify_options(struct verify_context
*vfy
)
239 opts
= mnt_fs_get_vfs_options(vfy
->fs
);
241 verify_ok(vfy
, _("VFS options: %s"), opts
);
243 opts
= mnt_fs_get_fs_options(vfy
->fs
);
245 verify_ok(vfy
, _("FS options: %s"), opts
);
247 opts
= mnt_fs_get_user_options(vfy
->fs
);
249 verify_ok(vfy
, _("userspace options: %s"), opts
);
254 static int verify_swaparea(struct verify_context
*vfy
)
259 if (mnt_fs_get_option(vfy
->fs
, "discard", &arg
, &argsz
) == 0
261 && strncmp(arg
, "once", argsz
) != 0
262 && strncmp(arg
, "pages", argsz
) != 0)
263 verify_err(vfy
, _("unsupported swaparea discard policy: %s"), arg
);
265 if (mnt_fs_get_option(vfy
->fs
, "pri", &arg
, &argsz
) == 0 && arg
) {
269 for (; p
< arg
+ argsz
; p
++) {
270 if (!isdigit((unsigned char) *p
)) {
271 verify_err(vfy
, _("failed to parse swaparea priority option"));
280 static int is_supported_filesystem(struct verify_context
*vfy
, const char *name
)
287 for (n
= 0; n
< vfy
->fs_num
; n
++ ) {
288 if (match_fstype(vfy
->fs_ary
[n
], name
))
295 static int add_filesystem(struct verify_context
*vfy
, const char *name
)
299 if (is_supported_filesystem(vfy
, name
))
302 if (vfy
->fs_alloc
== 0 || vfy
->fs_num
+ 1 <= vfy
->fs_alloc
) {
303 vfy
->fs_alloc
= ((vfy
->fs_alloc
+ 1 + MYCHUNK
) / MYCHUNK
) * MYCHUNK
;
304 vfy
->fs_ary
= xreallocarray(vfy
->fs_ary
, vfy
->fs_alloc
, sizeof(char *));
307 vfy
->fs_ary
[vfy
->fs_num
] = xstrdup(name
);
313 static int read_proc_filesystems(struct verify_context
*vfy
)
317 char buf
[80], *cp
, *t
;
319 f
= fopen("/proc/filesystems", "r");
324 if (!fgets(buf
, sizeof(buf
), f
))
328 while (*cp
&& !isspace(*cp
))
331 while (*cp
&& isspace(*cp
))
333 if ((t
= strchr(cp
, '\n')) != NULL
)
335 if ((t
= strchr(cp
, '\t')) != NULL
)
337 if ((t
= strchr(cp
, ' ')) != NULL
)
340 rc
= add_filesystem(vfy
, cp
);
348 static void free_proc_filesystems(struct verify_context
*vfy
)
355 for (n
= 0; n
< vfy
->fs_num
; n
++ )
356 free(vfy
->fs_ary
[n
]);
360 static int read_kernel_filesystems(struct verify_context
*vfy
)
370 snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
379 if (!fgets(buf
, sizeof(buf
), f
))
382 if (strncmp("kernel/fs/", buf
, 10) != 0 ||
383 strncmp("kernel/fs/nls/", buf
, 14) == 0)
386 p
= strchr(buf
, ':');
391 name
= strrchr(buf
, '/');
396 p
= strstr(name
, ".ko");
401 rc
= add_filesystem(vfy
, name
);
406 #endif /* __linux__ */
410 static int verify_fstype(struct verify_context
*vfy
)
412 char *src
= mnt_resolve_spec(mnt_fs_get_source(vfy
->fs
), cache
);
413 char *realtype
= NULL
;
415 int ambi
= 0, isauto
= 0, isswap
= 0;
420 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
)) {
421 verify_ok(vfy
, _("do not check %s FS type (pseudo/net)"), src
);
425 type
= mnt_fs_get_fstype(vfy
->fs
);
428 int none
= strcmp(type
, "none") == 0;
431 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1
432 && mnt_fs_get_option(vfy
->fs
, "move", NULL
, NULL
) == 1) {
433 verify_warn(vfy
, _("\"none\" FS type is recommended for bind or move oprations only"));
437 if (strcmp(type
, "auto") == 0)
439 else if (strcmp(type
, "swap") == 0)
441 else if (strcmp(type
, "xfs") == 0 || strcmp(type
, "btrfs") == 0)
444 if (!isswap
&& !isauto
&& !none
&& !is_supported_filesystem(vfy
, type
))
445 verify_warn(vfy
, _("%s seems unsupported by the current kernel"), type
);
449 realtype
= mnt_get_fstype(src
, &ambi
, cache
);
452 const char *reson
= errno
? strerror(errno
) : _("reason unknown");
455 verify_err(vfy
, _("cannot detect on-disk filesystem type (%s)"), reson
);
457 verify_warn(vfy
, _("cannot detect on-disk filesystem type (%s)"), reson
);
462 isswap
= strcmp(realtype
, "swap") == 0;
463 vfy
->no_fsck
= strcmp(realtype
, "xfs") == 0
464 || strcmp(realtype
, "btrfs") == 0;
466 if (type
&& !isauto
&& strcmp(type
, realtype
) != 0) {
467 verify_warn(vfy
, _("%s does not match with on-disk %s"), type
, realtype
);
470 if (!isswap
&& !is_supported_filesystem(vfy
, realtype
)) {
471 verify_warn(vfy
, _("on-disk %s seems unsupported by the current kernel"), realtype
);
475 verify_ok(vfy
, _("FS type is %s"), realtype
);
486 static int verify_passno(struct verify_context
*vfy
)
488 int passno
= mnt_fs_get_passno(vfy
->fs
);
489 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
491 if (tgt
&& strcmp("/", tgt
) == 0 && passno
!= 1 && !vfy
->no_fsck
)
492 return verify_warn(vfy
, _("recommended root FS passno is 1 (current is %d)"), passno
);
497 static int verify_filesystem(struct verify_context
*vfy
)
501 if (mnt_fs_is_swaparea(vfy
->fs
))
502 rc
= verify_swaparea(vfy
);
504 rc
= verify_target(vfy
);
506 rc
= verify_options(vfy
);
510 rc
= verify_source(vfy
);
512 rc
= verify_fstype(vfy
);
514 rc
= verify_passno(vfy
); /* depends on verify_fstype() */
519 int verify_table(struct libmnt_table
*tb
)
521 struct verify_context vfy
= { .nerrors
= 0 };
522 struct libmnt_iter
*itr
;
523 int rc
= 0; /* overall return code (alloc errors, etc.) */
524 int check_order
= is_listall_mode();
525 static int has_read_fs
= 0;
527 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
529 warn(_("failed to initialize libmount iterator"));
535 if (has_read_fs
== 0) {
536 read_proc_filesystems(&vfy
);
537 read_kernel_filesystems(&vfy
);
541 while (rc
== 0 && (vfy
.fs
= get_next_fs(tb
, itr
))) {
542 vfy
.target_printed
= 0;
546 rc
= verify_order(&vfy
);
548 rc
= verify_filesystem(&vfy
);
550 if (flags
& FL_FIRSTONLY
)
552 flags
|= FL_NOSWAPMATCH
;
559 if (stat(_PATH_SD_UNITSLOAD
, &a
) == 0 &&
560 stat(_PATH_MNTTAB
, &b
) == 0 &&
561 cmp_stat_mtime(&a
, &b
, <))
563 "your fstab has been modified, but systemd still uses the old version;\n"
564 " use 'systemctl daemon-reload' to reload"));
572 if (vfy
.nerrors
|| parse_nerrors
|| vfy
.nwarnings
) {
574 fprintf(stderr
, P_("%d parse error", "%d parse errors", parse_nerrors
), parse_nerrors
);
575 fprintf(stderr
, P_(", %d error", ", %d errors", vfy
.nerrors
), vfy
.nerrors
);
576 fprintf(stderr
, P_(", %d warning", ", %d warnings", vfy
.nwarnings
), vfy
.nwarnings
);
579 fprintf(stdout
, _("Success, no errors or warnings detected\n"));
582 free_proc_filesystems(&vfy
);
584 return rc
!= 0 ? rc
: vfy
.nerrors
+ parse_nerrors
;