]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase5.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
10 #include <sys/statvfs.h>
12 # include <attr/attributes.h>
17 #include "libfrog/paths.h"
18 #include "libfrog/workqueue.h"
19 #include "xfs_scrub.h"
27 /* Phase 5: Check directory connectivity. */
30 * Warn about problematic bytes in a directory/attribute name. That means
31 * terminal control characters and escape sequences, since that could be used
32 * to do something naughty to the user's computer and/or break scripts. XFS
33 * doesn't consider any byte sequence invalid, so don't flag these as errors.
35 * Returns 0 for success or -1 for error. This function logs errors.
39 struct scrub_ctx
*ctx
,
41 const char *namedescr
,
48 /* Complain about zero length names. */
49 if (*name
== '\0' && should_warn_about_name(ctx
)) {
50 str_warn(ctx
, descr_render(dsc
), _("Zero length name found."));
54 /* control characters */
55 for (p
= name
; *p
; p
++) {
56 if ((*p
>= 1 && *p
<= 31) || *p
== 127) {
62 if (bad
&& should_warn_about_name(ctx
)) {
63 errname
= string_escape(name
);
65 str_errno(ctx
, descr_render(dsc
));
68 str_info(ctx
, descr_render(dsc
),
69 _("Control character found in %s name \"%s\"."),
78 * Iterate a directory looking for filenames with problematic
83 struct scrub_ctx
*ctx
,
86 struct xfs_bulkstat
*bstat
)
88 struct unicrash
*uc
= NULL
;
90 struct dirent
*dentry
;
95 str_errno(ctx
, descr_render(dsc
));
98 *fd
= -1; /* closedir will close *fd for us */
100 ret
= unicrash_dir_init(&uc
, ctx
, bstat
);
102 str_liberror(ctx
, ret
, descr_render(dsc
));
107 dentry
= readdir(dir
);
110 ret
= unicrash_check_dir_name(uc
, dsc
, dentry
);
112 ret
= simple_check_name(ctx
, dsc
, _("directory"),
115 str_liberror(ctx
, ret
, descr_render(dsc
));
119 dentry
= readdir(dir
);
123 str_liberror(ctx
, ret
, descr_render(dsc
));
133 /* Routines to scan all of an inode's xattrs for name problems. */
134 struct attrns_decode
{
139 static const struct attrns_decode attr_ns
[] = {
141 {ATTR_ROOT
, "system"},
142 {ATTR_SECURE
, "secure"},
147 * Check all the xattr names in a particular namespace of a file handle
148 * for Unicode normalization problems or collisions.
151 check_xattr_ns_names(
152 struct scrub_ctx
*ctx
,
154 struct xfs_handle
*handle
,
155 struct xfs_bulkstat
*bstat
,
156 const struct attrns_decode
*attr_ns
)
158 struct attrlist_cursor cur
;
159 char attrbuf
[XFS_XATTR_LIST_MAX
];
160 char keybuf
[XATTR_NAME_MAX
+ 1];
161 struct attrlist
*attrlist
= (struct attrlist
*)attrbuf
;
162 struct attrlist_ent
*ent
;
163 struct unicrash
*uc
= NULL
;
167 error
= unicrash_xattr_init(&uc
, ctx
, bstat
);
169 str_liberror(ctx
, error
, descr_render(dsc
));
173 memset(attrbuf
, 0, XFS_XATTR_LIST_MAX
);
174 memset(&cur
, 0, sizeof(cur
));
175 memset(keybuf
, 0, XATTR_NAME_MAX
+ 1);
176 error
= attr_list_by_handle(handle
, sizeof(*handle
), attrbuf
,
177 XFS_XATTR_LIST_MAX
, attr_ns
->flags
, &cur
);
179 /* Examine the xattrs. */
180 for (i
= 0; i
< attrlist
->al_count
; i
++) {
181 ent
= ATTR_ENTRY(attrlist
, i
);
182 snprintf(keybuf
, XATTR_NAME_MAX
, "%s.%s", attr_ns
->name
,
185 error
= unicrash_check_xattr_name(uc
, dsc
,
188 error
= simple_check_name(ctx
, dsc
,
189 _("extended attribute"),
192 str_liberror(ctx
, error
, descr_render(dsc
));
197 if (!attrlist
->al_more
)
199 error
= attr_list_by_handle(handle
, sizeof(*handle
), attrbuf
,
200 XFS_XATTR_LIST_MAX
, attr_ns
->flags
, &cur
);
206 str_errno(ctx
, descr_render(dsc
));
214 * Check all the xattr names in all the xattr namespaces for problematic
219 struct scrub_ctx
*ctx
,
221 struct xfs_handle
*handle
,
222 struct xfs_bulkstat
*bstat
)
224 const struct attrns_decode
*ns
;
227 for (ns
= attr_ns
; ns
->name
; ns
++) {
228 ret
= check_xattr_ns_names(ctx
, dsc
, handle
, bstat
, ns
);
235 # define check_xattr_names(c, d, h, b) (0)
236 #endif /* HAVE_LIBATTR */
239 render_ino_from_handle(
240 struct scrub_ctx
*ctx
,
245 struct xfs_bstat
*bstat
= data
;
247 return scrub_render_ino_descr(ctx
, buf
, buflen
, bstat
->bs_ino
,
248 bstat
->bs_gen
, NULL
);
252 * Verify the connectivity of the directory tree.
253 * We know that the kernel's open-by-handle function will try to reconnect
254 * parents of an opened directory, so we'll accept that as sufficient.
256 * Check for potential Unicode collisions in names.
260 struct scrub_ctx
*ctx
,
261 struct xfs_handle
*handle
,
262 struct xfs_bulkstat
*bstat
,
265 DEFINE_DESCR(dsc
, ctx
, render_ino_from_handle
);
271 descr_set(&dsc
, bstat
);
274 /* Warn about naming problems in xattrs. */
275 if (bstat
->bs_xflags
& FS_XFLAG_HASATTR
) {
276 error
= check_xattr_names(ctx
, &dsc
, handle
, bstat
);
281 /* Open the dir, let the kernel try to reconnect it to the root. */
282 if (S_ISDIR(bstat
->bs_mode
)) {
283 fd
= scrub_open_handle(handle
);
288 str_errno(ctx
, descr_render(&dsc
));
293 /* Warn about naming problems in the directory entries. */
294 if (fd
>= 0 && S_ISDIR(bstat
->bs_mode
)) {
295 error
= check_dirent_names(ctx
, &dsc
, &fd
, bstat
);
305 str_errno(ctx
, descr_render(&dsc
));
312 if (!error
&& *aborted
)
318 #ifndef FS_IOC_GETFSLABEL
319 # define FSLABEL_MAX 256
320 # define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
321 #endif /* FS_IOC_GETFSLABEL */
324 scrub_render_mountpoint(
325 struct scrub_ctx
*ctx
,
330 return snprintf(buf
, buflen
, _("%s"), ctx
->mntpoint
);
334 * Check the filesystem label for Unicode normalization problems or misleading
339 struct scrub_ctx
*ctx
)
341 DEFINE_DESCR(dsc
, ctx
, scrub_render_mountpoint
);
342 char label
[FSLABEL_MAX
];
343 struct unicrash
*uc
= NULL
;
346 error
= unicrash_fs_label_init(&uc
, ctx
);
348 str_liberror(ctx
, error
, descr_render(&dsc
));
352 descr_set(&dsc
, NULL
);
354 /* Retrieve label; quietly bail if we don't support that. */
355 error
= ioctl(ctx
->mnt
.fd
, FS_IOC_GETFSLABEL
, &label
);
357 if (errno
!= EOPNOTSUPP
&& errno
!= ENOTTY
) {
359 perror(ctx
->mntpoint
);
364 /* Ignore empty labels. */
368 /* Otherwise check for weirdness. */
370 error
= unicrash_check_fs_label(uc
, &dsc
, label
);
372 error
= simple_check_name(ctx
, &dsc
, _("filesystem label"),
375 str_liberror(ctx
, error
, descr_render(&dsc
));
381 /* Check directory connectivity. */
384 struct scrub_ctx
*ctx
)
386 bool aborted
= false;
389 if (ctx
->corruptions_found
|| ctx
->unfixable_errors
) {
390 str_info(ctx
, ctx
->mntpoint
,
391 _("Filesystem has errors, skipping connectivity checks."));
395 ret
= check_fs_label(ctx
);
399 ret
= scrub_scan_all_inodes(ctx
, check_inode_names
, &aborted
);
405 xfs_scrub_report_preen_triggers(ctx
);
409 /* Estimate how much work we're going to do. */
412 struct scrub_ctx
*ctx
,
414 unsigned int *nr_threads
,
417 *items
= ctx
->mnt_sv
.f_files
- ctx
->mnt_sv
.f_ffree
;
418 *nr_threads
= scrub_nproc(ctx
);