]>
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;
34 static void verify_mesg(struct verify_context
*vfy
, char type
, const char *fmt
, va_list ap
)
36 if (!vfy
->target_printed
) {
37 fprintf(stdout
, "%s\n", mnt_fs_get_target(vfy
->fs
));
38 vfy
->target_printed
= 1;
41 fprintf(stdout
, " [%c] ", type
);
42 vfprintf(stdout
, fmt
, ap
);
46 static int verify_warn(struct verify_context
*vfy
, const char *fmt
, ...)
51 verify_mesg(vfy
, 'W', fmt
, ap
);
56 static int verify_err(struct verify_context
*vfy
, const char *fmt
, ...)
61 verify_mesg(vfy
, 'E', fmt
, ap
);
66 static int verify_ok(struct verify_context
*vfy
__attribute__((unused
)),
71 if (!(flags
& FL_VERBOSE
))
75 verify_mesg(vfy
, ' ', fmt
, ap
);
80 static int verify_order(struct verify_context
*vfy
)
82 struct libmnt_iter
*itr
= NULL
;
83 struct libmnt_fs
*next
;
86 tgt
= mnt_fs_get_target(vfy
->fs
);
87 if (tgt
&& !(flags
& FL_NOCACHE
))
88 tgt
= mnt_resolve_target(tgt
, cache
);
92 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
94 warn(_("failed to initialize libmount iterator"));
98 /* set iterator position to 'fs' */
99 mnt_table_set_iter(vfy
->tb
, itr
, vfy
->fs
);
100 mnt_table_next_fs(vfy
->tb
, itr
, &next
);
102 /* scan all next filesystems */
103 while (mnt_table_next_fs(vfy
->tb
, itr
, &next
) == 0) {
107 n_tgt
= mnt_fs_get_target(next
);
108 if (n_tgt
&& !(flags
& FL_NOCACHE
))
109 n_tgt
= mnt_resolve_target(n_tgt
, cache
);
114 if (strncmp(n_tgt
, tgt
, len
) == 0) {
115 if (*(tgt
+ len
) == '\0')
116 verify_warn(vfy
, _("target specified more than once"));
117 else if (*(tgt
+ len
) == '/')
118 verify_err(vfy
, _("wrong order: %s specified before %s"), tgt
, n_tgt
);
126 static int verify_target(struct verify_context
*vfy
)
128 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
132 return verify_err(vfy
, _("undefined target (fs_file)"));
134 if (!(flags
& FL_NOCACHE
)) {
135 const char *cn
= mnt_resolve_target(tgt
, cache
);
138 if (strcmp(cn
, tgt
) != 0)
139 verify_warn(vfy
, _("non-canonical target path (real: %s)"), cn
);
142 if (stat(tgt
, &sb
) != 0) {
143 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
144 verify_err(vfy
, _("unreachable on boot required target: %m"));
146 verify_warn(vfy
, _("unreachable target: %m"));
148 } else if (!S_ISDIR(sb
.st_mode
)
149 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1) {
150 verify_err(vfy
, _("target is not a directory"));
152 verify_ok(vfy
, _("target exists"));
157 static char *verify_tag(struct verify_context
*vfy
, const char *name
,
160 char *src
= mnt_resolve_tag(name
, value
, cache
);
163 if (mnt_fs_get_option(vfy
->fs
, "noauto", NULL
, NULL
) == 1)
164 verify_err(vfy
, _("unreachable on boot required source: %s=%s"), name
, value
);
166 verify_warn(vfy
, _("unreachable: %s=%s"), name
, value
);
168 verify_ok(vfy
, _("%s=%s translated to %s"), name
, value
, src
);
173 /* Note that mount source is very FS specific and we should not
174 * interpret unreachable source as error. The exception is only
175 * NAME=value, this has to be convertible to device name.
177 static int verify_source(struct verify_context
*vfy
)
179 const char *src
= mnt_fs_get_srcpath(vfy
->fs
);
180 char *t
= NULL
, *v
= NULL
;
184 /* source is NAME=value tag */
186 const char *tag
= NULL
, *val
= NULL
;
188 if (mnt_fs_get_tag(vfy
->fs
, &tag
, &val
) != 0)
189 return verify_err(vfy
, _("undefined source (fs_spec)"));
191 src
= verify_tag(vfy
, tag
, val
);
195 /* blkid is able to parse it, but libmount does not see it as a tag --
196 * it means unsupported tag */
197 } else if (blkid_parse_tag_string(src
, &t
, &v
) == 0 && stat(src
, &sb
) != 0) {
198 rc
= verify_err(vfy
, _("unsupported source tag: %s"), src
);
201 isbind
= mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 0;
204 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
))
205 verify_ok(vfy
, _("do not check %s source (pseudo/net)"), src
);
207 else if (stat(src
, &sb
) != 0)
208 verify_warn(vfy
, _("unreachable source: %s: %m"), src
);
210 else if ((S_ISDIR(sb
.st_mode
) || S_ISREG(sb
.st_mode
)) && !isbind
)
211 verify_warn(vfy
, _("non-bind mount source %s is a directory or regular file"), src
);
213 else if (!S_ISBLK(sb
.st_mode
) && !isbind
)
214 verify_warn(vfy
, _("source %s is not a block device"), src
);
216 verify_ok(vfy
, _("source %s exists"), src
);
223 static int verify_options(struct verify_context
*vfy
)
227 opts
= mnt_fs_get_vfs_options(vfy
->fs
);
229 verify_ok(vfy
, _("VFS options: %s"), opts
);
231 opts
= mnt_fs_get_fs_options(vfy
->fs
);
233 verify_ok(vfy
, _("FS options: %s"), opts
);
235 opts
= mnt_fs_get_user_options(vfy
->fs
);
237 verify_ok(vfy
, _("userspace options: %s"), opts
);
242 static int verify_swaparea(struct verify_context
*vfy
)
247 if (mnt_fs_get_option(vfy
->fs
, "discard", &arg
, &argsz
) == 0
249 && strncmp(arg
, "once", argsz
) != 0
250 && strncmp(arg
, "pages", argsz
) != 0)
251 verify_err(vfy
, _("unsupported swaparea discard policy: %s"), arg
);
253 if (mnt_fs_get_option(vfy
->fs
, "pri", &arg
, &argsz
) == 0 && arg
) {
257 for (; p
< arg
+ argsz
; p
++) {
258 if (!isdigit((unsigned char) *p
)) {
259 verify_err(vfy
, _("failed to parse swaparea priority option"));
268 static int is_supported_filesystem(struct verify_context
*vfy
, const char *name
)
275 for (n
= 0; n
< vfy
->fs_num
; n
++ ) {
276 if (strcmp(vfy
->fs_ary
[n
], name
) == 0)
283 static int add_filesystem(struct verify_context
*vfy
, const char *name
)
287 if (is_supported_filesystem(vfy
, name
))
290 if (vfy
->fs_alloc
== 0 || vfy
->fs_num
+ 1 <= vfy
->fs_alloc
) {
291 vfy
->fs_alloc
= ((vfy
->fs_alloc
+ 1 + MYCHUNK
) / MYCHUNK
) * MYCHUNK
;
292 vfy
->fs_ary
= xrealloc(vfy
->fs_ary
, vfy
->fs_alloc
* sizeof(char *));
295 vfy
->fs_ary
[vfy
->fs_num
] = xstrdup(name
);
301 static int read_proc_filesystems(struct verify_context
*vfy
)
305 char buf
[80], *cp
, *t
;
307 f
= fopen("/proc/filesystems", "r");
312 if (!fgets(buf
, sizeof(buf
), f
))
316 while (*cp
&& !isspace(*cp
))
319 while (*cp
&& isspace(*cp
))
321 if ((t
= strchr(cp
, '\n')) != NULL
)
323 if ((t
= strchr(cp
, '\t')) != NULL
)
325 if ((t
= strchr(cp
, ' ')) != NULL
)
328 rc
= add_filesystem(vfy
, cp
);
336 static int read_kernel_filesystems(struct verify_context
*vfy
)
346 snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
355 if (!fgets(buf
, sizeof(buf
), f
))
358 if (strncmp("kernel/fs/", buf
, 10) != 0 ||
359 strncmp("kernel/fs/nls/", buf
, 14) == 0)
362 p
= strchr(buf
, ':');
367 name
= strrchr(buf
, '/');
372 p
= strstr(name
, ".ko");
377 rc
= add_filesystem(vfy
, name
);
382 #endif /* __linux__ */
386 static int verify_fstype(struct verify_context
*vfy
)
388 const char *src
= mnt_resolve_spec(mnt_fs_get_source(vfy
->fs
), cache
);
389 const char *type
, *realtype
;
390 int ambi
= 0, isauto
= 0, isswap
= 0;
394 if (mnt_fs_is_pseudofs(vfy
->fs
) || mnt_fs_is_netfs(vfy
->fs
))
395 return verify_ok(vfy
, _("do not check %s FS type (pseudo/net)"), src
);
397 type
= mnt_fs_get_fstype(vfy
->fs
);
400 int none
= strcmp(type
, "none") == 0;
403 && mnt_fs_get_option(vfy
->fs
, "bind", NULL
, NULL
) == 1
404 && mnt_fs_get_option(vfy
->fs
, "move", NULL
, NULL
) == 1)
405 return verify_warn(vfy
, _("\"none\" FS type is recommended for bind or move oprations only"));
407 else if (strcmp(type
, "auto") == 0)
409 else if (strcmp(type
, "swap") == 0)
412 if (!isswap
&& !isauto
&& !none
&& !is_supported_filesystem(vfy
, type
))
413 verify_warn(vfy
, _("%s seems unsupported by the current kernel"), type
);
415 realtype
= mnt_get_fstype(src
, &ambi
, cache
);
419 return verify_err(vfy
, _("cannot detect on-disk filesystem type"));
420 return verify_warn(vfy
, _("cannot detect on-disk filesystem type"));
424 isswap
= strcmp(realtype
, "swap") == 0;
426 if (type
&& !isauto
&& strcmp(type
, realtype
) != 0)
427 return verify_err(vfy
, _("%s does not match with on-disk %s"), type
, realtype
);
429 if (!isswap
&& !is_supported_filesystem(vfy
, realtype
))
430 return verify_err(vfy
, _("on-disk %s seems unsupported by the current kernel"), realtype
);
432 verify_ok(vfy
, _("FS type is %s"), realtype
);
438 static int verify_passno(struct verify_context
*vfy
)
440 int passno
= mnt_fs_get_passno(vfy
->fs
);
441 const char *tgt
= mnt_fs_get_target(vfy
->fs
);
443 if (tgt
&& strcmp("/", tgt
) == 0 && passno
!= 1)
444 return verify_warn(vfy
, _("recommended root FS passno is 1 (current is %d)"), passno
);
449 static int verify_filesystem(struct verify_context
*vfy
)
453 if (mnt_fs_is_swaparea(vfy
->fs
))
454 rc
= verify_swaparea(vfy
);
456 rc
= verify_target(vfy
);
458 rc
= verify_options(vfy
);
462 rc
= verify_source(vfy
);
464 rc
= verify_fstype(vfy
);
466 rc
= verify_passno(vfy
);
471 int verify_table(struct libmnt_table
*tb
)
473 struct verify_context vfy
= { .nerrors
= 0 };
474 struct libmnt_iter
*itr
;
475 int rc
= 0; /* overall return code (alloc errors, etc.) */
476 int check_order
= is_listall_mode();
477 static int has_read_fs
= 0;
479 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
481 warn(_("failed to initialize libmount iterator"));
487 if (has_read_fs
== 0) {
488 read_proc_filesystems(&vfy
);
489 read_kernel_filesystems(&vfy
);
493 while (rc
== 0 && (vfy
.fs
= get_next_fs(tb
, itr
))) {
494 vfy
.target_printed
= 0;
496 rc
= verify_order(&vfy
);
498 rc
= verify_filesystem(&vfy
);
500 if (flags
& FL_FIRSTONLY
)
502 flags
|= FL_NOSWAPMATCH
;
509 if (vfy
.nerrors
|| parse_nerrors
|| vfy
.nwarnings
) {
511 fprintf(stderr
, P_("%d parse error", "%d parse errors", parse_nerrors
), parse_nerrors
);
512 fprintf(stderr
, P_(", %d error", ", %d errors", vfy
.nerrors
), vfy
.nerrors
);
513 fprintf(stderr
, P_(", %d warning", ", %d warnings", vfy
.nwarnings
), vfy
.nwarnings
);
516 fprintf(stdout
, _("Success, no errors or warnings detected\n"));
518 return rc
!= 0 ? rc
: vfy
.nerrors
+ parse_nerrors
;