]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/findmnt-verify.c
11 #include <sys/utsname.h>
20 struct verify_context
{
22 struct libmnt_table
*tb
;
31 unsigned int target_printed
: 1,
35 static void verify_mesg(struct verify_context
*vfy
, char type
, const char *fmt
, va_list ap
)
37 if (!vfy
->target_printed
) {
38 fprintf(stdout
, "%s\n", mnt_fs_get_target(vfy
->fs
));
39 vfy
->target_printed
= 1;
42 fprintf(stdout
, " [%c] ", type
);
43 vfprintf(stdout
, fmt
, ap
);
47 static int verify_warn(struct verify_context
*vfy
, const char *fmt
, ...)
52 verify_mesg(vfy
, 'W', fmt
, ap
);
57 static int verify_err(struct verify_context
*vfy
, const char *fmt
, ...)
62 verify_mesg(vfy
, 'E', fmt
, ap
);
67 static int verify_ok(struct verify_context
*vfy
__attribute__((unused
)),
72 if (!(flags
& FL_VERBOSE
))
76 verify_mesg(vfy
, ' ', fmt
, ap
);
81 static int verify_order(struct verify_context
*vfy
)
83 struct libmnt_iter
*itr
= NULL
;
84 struct libmnt_fs
*next
;
87 tgt
= mnt_fs_get_target(vfy
->fs
);
88 if (tgt
&& !(flags
& FL_NOCACHE
))
89 tgt
= mnt_resolve_target(tgt
, cache
);
93 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
95 warn(_("failed to initialize libmount iterator"));
99 /* set iterator position to 'fs' */
100 mnt_table_set_iter(vfy
->tb
, itr
, vfy
->fs
);
102 if (mnt_table_next_fs(vfy
->tb
, itr
, &next
) != 0)
105 /* scan all next filesystems */
106 while (mnt_table_next_fs(vfy
->tb
, itr
, &next
) == 0) {
110 n_tgt
= mnt_fs_get_target(next
);
111 if (n_tgt
&& !(flags
& FL_NOCACHE
))
112 n_tgt
= mnt_resolve_target(n_tgt
, cache
);
117 if (strncmp(n_tgt
, tgt
, len
) == 0) {
118 if (*(tgt
+ len
) == '\0')
119 verify_warn(vfy
, _("target specified more than once"));
120 else if (*(tgt
+ len
) == '/')
121 verify_err(vfy
, _("wrong order: %s specified before %s"), tgt
, n_tgt
);
129 static int verify_target(struct verify_context
*vfy
)
131 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
135 return verify_err(vfy
, _("undefined target (fs_file)"));
137 if (!(flags
& FL_NOCACHE
)) {
138 const char *cn
= mnt_resolve_target(tgt
, cache
);
141 if (strcmp(cn
, tgt
) != 0)
142 verify_warn(vfy
, _("non-canonical target path (real: %s)"), cn
);
145 if (stat(tgt
, &sb
) != 0) {
146 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
147 verify_err(vfy
, _("unreachable on boot required target: %m"));
149 verify_warn(vfy
, _("unreachable target: %m"));
151 } else if (!S_ISDIR(sb
.st_mode
)
152 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1) {
153 verify_err(vfy
, _("target is not a directory"));
155 verify_ok(vfy
, _("target exists"));
160 static char *verify_tag(struct verify_context
*vfy
, const char *name
,
163 char *src
= mnt_resolve_tag(name
, value
, cache
);
166 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
167 verify_err(vfy
, _("unreachable on boot required source: %s=%s"), name
, value
);
169 verify_warn(vfy
, _("unreachable: %s=%s"), name
, value
);
171 verify_ok(vfy
, _("%s=%s translated to %s"), name
, value
, src
);
176 /* Note that mount source is very FS specific and we should not
177 * interpret unreachable source as error. The exception is only
178 * NAME=value, this has to be convertible to device name.
180 static int verify_source(struct verify_context
*vfy
)
182 const char *src
= mnt_fs_get_srcpath(vfy
->fs
);
183 char *t
= NULL
, *v
= NULL
;
187 /* source is NAME=value tag */
189 const char *tag
= NULL
, *val
= NULL
;
191 if (mnt_fs_get_tag(vfy
->fs
, &tag
, &val
) != 0)
192 return verify_err(vfy
, _("undefined source (fs_spec)"));
194 src
= verify_tag(vfy
, tag
, val
);
198 /* blkid is able to parse it, but libmount does not see it as a tag --
199 * it means unsupported tag */
200 } else if (blkid_parse_tag_string(src
, &t
, &v
) == 0 && stat(src
, &sb
) != 0) {
201 rc
= verify_err(vfy
, _("unsupported source tag: %s"), src
);
204 isbind
= mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 0;
207 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
))
208 verify_ok(vfy
, _("do not check %s source (pseudo/net)"), src
);
210 else if (stat(src
, &sb
) != 0)
211 verify_warn(vfy
, _("unreachable source: %s: %m"), src
);
213 else if ((S_ISDIR(sb
.st_mode
) || S_ISREG(sb
.st_mode
)) && !isbind
)
214 verify_warn(vfy
, _("non-bind mount source %s is a directory or regular file"), src
);
216 else if (!S_ISBLK(sb
.st_mode
) && !isbind
)
217 verify_warn(vfy
, _("source %s is not a block device"), src
);
219 verify_ok(vfy
, _("source %s exists"), src
);
226 static int verify_options(struct verify_context
*vfy
)
230 opts
= mnt_fs_get_vfs_options(vfy
->fs
);
232 verify_ok(vfy
, _("VFS options: %s"), opts
);
234 opts
= mnt_fs_get_fs_options(vfy
->fs
);
236 verify_ok(vfy
, _("FS options: %s"), opts
);
238 opts
= mnt_fs_get_user_options(vfy
->fs
);
240 verify_ok(vfy
, _("userspace options: %s"), opts
);
245 static int verify_swaparea(struct verify_context
*vfy
)
250 if (mnt_fs_get_option(vfy
->fs
, "discard", &arg
, &argsz
) == 0
252 && strncmp(arg
, "once", argsz
) != 0
253 && strncmp(arg
, "pages", argsz
) != 0)
254 verify_err(vfy
, _("unsupported swaparea discard policy: %s"), arg
);
256 if (mnt_fs_get_option(vfy
->fs
, "pri", &arg
, &argsz
) == 0 && arg
) {
260 for (; p
< arg
+ argsz
; p
++) {
261 if (!isdigit((unsigned char) *p
)) {
262 verify_err(vfy
, _("failed to parse swaparea priority option"));
271 static int is_supported_filesystem(struct verify_context
*vfy
, const char *name
)
278 for (n
= 0; n
< vfy
->fs_num
; n
++ ) {
279 if (strcmp(vfy
->fs_ary
[n
], name
) == 0)
286 static int add_filesystem(struct verify_context
*vfy
, const char *name
)
290 if (is_supported_filesystem(vfy
, name
))
293 if (vfy
->fs_alloc
== 0 || vfy
->fs_num
+ 1 <= vfy
->fs_alloc
) {
294 vfy
->fs_alloc
= ((vfy
->fs_alloc
+ 1 + MYCHUNK
) / MYCHUNK
) * MYCHUNK
;
295 vfy
->fs_ary
= xrealloc(vfy
->fs_ary
, vfy
->fs_alloc
* sizeof(char *));
298 vfy
->fs_ary
[vfy
->fs_num
] = xstrdup(name
);
304 static int read_proc_filesystems(struct verify_context
*vfy
)
308 char buf
[80], *cp
, *t
;
310 f
= fopen("/proc/filesystems", "r");
315 if (!fgets(buf
, sizeof(buf
), f
))
319 while (*cp
&& !isspace(*cp
))
322 while (*cp
&& isspace(*cp
))
324 if ((t
= strchr(cp
, '\n')) != NULL
)
326 if ((t
= strchr(cp
, '\t')) != NULL
)
328 if ((t
= strchr(cp
, ' ')) != NULL
)
331 rc
= add_filesystem(vfy
, cp
);
339 static int read_kernel_filesystems(struct verify_context
*vfy
)
349 snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
358 if (!fgets(buf
, sizeof(buf
), f
))
361 if (strncmp("kernel/fs/", buf
, 10) != 0 ||
362 strncmp("kernel/fs/nls/", buf
, 14) == 0)
365 p
= strchr(buf
, ':');
370 name
= strrchr(buf
, '/');
375 p
= strstr(name
, ".ko");
380 rc
= add_filesystem(vfy
, name
);
385 #endif /* __linux__ */
389 static int verify_fstype(struct verify_context
*vfy
)
391 const char *src
= mnt_resolve_spec(mnt_fs_get_source(vfy
->fs
), cache
);
392 const char *type
, *realtype
;
393 int ambi
= 0, isauto
= 0, isswap
= 0;
397 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
))
398 return verify_ok(vfy
, _("do not check %s FS type (pseudo/net)"), src
);
400 type
= mnt_fs_get_fstype(vfy
->fs
);
403 int none
= strcmp(type
, "none") == 0;
406 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1
407 && mnt_fs_get_option(vfy
->fs
, "move", NULL
, NULL
) == 1)
408 return verify_warn(vfy
, _("\"none\" FS type is recommended for bind or move oprations only"));
410 else if (strcmp(type
, "auto") == 0)
412 else if (strcmp(type
, "swap") == 0)
414 else if (strcmp(type
, "xfs") == 0)
417 if (!isswap
&& !isauto
&& !none
&& !is_supported_filesystem(vfy
, type
))
418 verify_warn(vfy
, _("%s seems unsupported by the current kernel"), type
);
420 realtype
= mnt_get_fstype(src
, &ambi
, cache
);
424 return verify_err(vfy
, _("cannot detect on-disk filesystem type"));
425 return verify_warn(vfy
, _("cannot detect on-disk filesystem type"));
429 isswap
= strcmp(realtype
, "swap") == 0;
430 vfy
->no_fsck
= strcmp(realtype
, "xfs") == 0;
432 if (type
&& !isauto
&& strcmp(type
, realtype
) != 0)
433 return verify_err(vfy
, _("%s does not match with on-disk %s"), type
, realtype
);
435 if (!isswap
&& !is_supported_filesystem(vfy
, realtype
))
436 return verify_err(vfy
, _("on-disk %s seems unsupported by the current kernel"), realtype
);
438 verify_ok(vfy
, _("FS type is %s"), realtype
);
444 static int verify_passno(struct verify_context
*vfy
)
446 int passno
= mnt_fs_get_passno(vfy
->fs
);
447 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
449 if (tgt
&& strcmp("/", tgt
) == 0 && passno
!= 1 && !vfy
->no_fsck
)
450 return verify_warn(vfy
, _("recommended root FS passno is 1 (current is %d)"), passno
);
455 static int verify_filesystem(struct verify_context
*vfy
)
459 if (mnt_fs_is_swaparea(vfy
->fs
))
460 rc
= verify_swaparea(vfy
);
462 rc
= verify_target(vfy
);
464 rc
= verify_options(vfy
);
468 rc
= verify_source(vfy
);
470 rc
= verify_fstype(vfy
);
472 rc
= verify_passno(vfy
); /* depends on verify_fstype() */
477 int verify_table(struct libmnt_table
*tb
)
479 struct verify_context vfy
= { .nerrors
= 0 };
480 struct libmnt_iter
*itr
;
481 int rc
= 0; /* overall return code (alloc errors, etc.) */
482 int check_order
= is_listall_mode();
483 static int has_read_fs
= 0;
485 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
487 warn(_("failed to initialize libmount iterator"));
493 if (has_read_fs
== 0) {
494 read_proc_filesystems(&vfy
);
495 read_kernel_filesystems(&vfy
);
499 while (rc
== 0 && (vfy
.fs
= get_next_fs(tb
, itr
))) {
500 vfy
.target_printed
= 0;
504 rc
= verify_order(&vfy
);
506 rc
= verify_filesystem(&vfy
);
508 if (flags
& FL_FIRSTONLY
)
510 flags
|= FL_NOSWAPMATCH
;
517 if (vfy
.nerrors
|| parse_nerrors
|| vfy
.nwarnings
) {
519 fprintf(stderr
, P_("%d parse error", "%d parse errors", parse_nerrors
), parse_nerrors
);
520 fprintf(stderr
, P_(", %d error", ", %d errors", vfy
.nerrors
), vfy
.nerrors
);
521 fprintf(stderr
, P_(", %d warning", ", %d warnings", vfy
.nwarnings
), vfy
.nwarnings
);
524 fprintf(stdout
, _("Success, no errors or warnings detected\n"));
526 return rc
!= 0 ? rc
: vfy
.nerrors
+ parse_nerrors
;