]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase5.c
e0c4a3dfafad4cc0defcb7500a35914ff6f89a17
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"
26 /* Phase 5: Check directory connectivity. */
29 * Warn about problematic bytes in a directory/attribute name. That means
30 * terminal control characters and escape sequences, since that could be used
31 * to do something naughty to the user's computer and/or break scripts. XFS
32 * doesn't consider any byte sequence invalid, so don't flag these as errors.
36 struct scrub_ctx
*ctx
,
38 const char *namedescr
,
45 /* Complain about zero length names. */
46 if (*name
== '\0' && should_warn_about_name(ctx
)) {
47 str_warn(ctx
, descr
, _("Zero length name found."));
51 /* control characters */
52 for (p
= name
; *p
; p
++) {
53 if ((*p
>= 1 && *p
<= 31) || *p
== 127) {
59 if (bad
&& should_warn_about_name(ctx
)) {
60 errname
= string_escape(name
);
62 str_errno(ctx
, descr
);
66 _("Control character found in %s name \"%s\"."),
75 * Iterate a directory looking for filenames with problematic
79 xfs_scrub_scan_dirents(
80 struct scrub_ctx
*ctx
,
83 struct xfs_bulkstat
*bstat
)
85 struct unicrash
*uc
= NULL
;
87 struct dirent
*dentry
;
92 str_errno(ctx
, descr
);
95 *fd
= -1; /* closedir will close *fd for us */
97 moveon
= unicrash_dir_init(&uc
, ctx
, bstat
);
101 dentry
= readdir(dir
);
104 moveon
= unicrash_check_dir_name(uc
, descr
, dentry
);
106 moveon
= xfs_scrub_check_name(ctx
, descr
,
107 _("directory"), dentry
->d_name
);
110 dentry
= readdir(dir
);
121 /* Routines to scan all of an inode's xattrs for name problems. */
122 struct attrns_decode
{
127 static const struct attrns_decode attr_ns
[] = {
129 {ATTR_ROOT
, "system"},
130 {ATTR_SECURE
, "secure"},
135 * Check all the xattr names in a particular namespace of a file handle
136 * for Unicode normalization problems or collisions.
139 xfs_scrub_scan_fhandle_namespace_xattrs(
140 struct scrub_ctx
*ctx
,
142 struct xfs_handle
*handle
,
143 struct xfs_bulkstat
*bstat
,
144 const struct attrns_decode
*attr_ns
)
146 struct attrlist_cursor cur
;
147 char attrbuf
[XFS_XATTR_LIST_MAX
];
148 char keybuf
[XATTR_NAME_MAX
+ 1];
149 struct attrlist
*attrlist
= (struct attrlist
*)attrbuf
;
150 struct attrlist_ent
*ent
;
151 struct unicrash
*uc
= NULL
;
156 moveon
= unicrash_xattr_init(&uc
, ctx
, bstat
);
160 memset(attrbuf
, 0, XFS_XATTR_LIST_MAX
);
161 memset(&cur
, 0, sizeof(cur
));
162 memset(keybuf
, 0, XATTR_NAME_MAX
+ 1);
163 error
= attr_list_by_handle(handle
, sizeof(*handle
), attrbuf
,
164 XFS_XATTR_LIST_MAX
, attr_ns
->flags
, &cur
);
166 /* Examine the xattrs. */
167 for (i
= 0; i
< attrlist
->al_count
; i
++) {
168 ent
= ATTR_ENTRY(attrlist
, i
);
169 snprintf(keybuf
, XATTR_NAME_MAX
, "%s.%s", attr_ns
->name
,
172 moveon
= unicrash_check_xattr_name(uc
, descr
,
175 moveon
= xfs_scrub_check_name(ctx
, descr
,
176 _("extended attribute"),
182 if (!attrlist
->al_more
)
184 error
= attr_list_by_handle(handle
, sizeof(*handle
), attrbuf
,
185 XFS_XATTR_LIST_MAX
, attr_ns
->flags
, &cur
);
187 if (error
&& errno
!= ESTALE
)
188 str_errno(ctx
, descr
);
195 * Check all the xattr names in all the xattr namespaces for problematic
199 xfs_scrub_scan_fhandle_xattrs(
200 struct scrub_ctx
*ctx
,
202 struct xfs_handle
*handle
,
203 struct xfs_bulkstat
*bstat
)
205 const struct attrns_decode
*ns
;
208 for (ns
= attr_ns
; ns
->name
; ns
++) {
209 moveon
= xfs_scrub_scan_fhandle_namespace_xattrs(ctx
, descr
,
217 # define xfs_scrub_scan_fhandle_xattrs(c, d, h, b) (true)
218 #endif /* HAVE_LIBATTR */
221 * Verify the connectivity of the directory tree.
222 * We know that the kernel's open-by-handle function will try to reconnect
223 * parents of an opened directory, so we'll accept that as sufficient.
225 * Check for potential Unicode collisions in names.
228 xfs_scrub_connections(
229 struct scrub_ctx
*ctx
,
230 struct xfs_handle
*handle
,
231 struct xfs_bulkstat
*bstat
,
235 char descr
[DESCR_BUFSZ
];
240 scrub_render_ino_descr(ctx
, descr
, DESCR_BUFSZ
, bstat
->bs_ino
,
241 bstat
->bs_gen
, NULL
);
244 /* Warn about naming problems in xattrs. */
245 if (bstat
->bs_xflags
& FS_XFLAG_HASATTR
) {
246 moveon
= xfs_scrub_scan_fhandle_xattrs(ctx
, descr
, handle
,
252 /* Open the dir, let the kernel try to reconnect it to the root. */
253 if (S_ISDIR(bstat
->bs_mode
)) {
254 fd
= xfs_open_handle(handle
);
258 str_errno(ctx
, descr
);
263 /* Warn about naming problems in the directory entries. */
264 if (fd
>= 0 && S_ISDIR(bstat
->bs_mode
)) {
265 moveon
= xfs_scrub_scan_dirents(ctx
, descr
, &fd
, bstat
);
275 str_errno(ctx
, descr
);
279 return *pmoveon
? 0 : XFS_ITERATE_INODES_ABORT
;
282 #ifndef FS_IOC_GETFSLABEL
283 # define FSLABEL_MAX 256
284 # define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
285 #endif /* FS_IOC_GETFSLABEL */
288 * Check the filesystem label for Unicode normalization problems or misleading
293 struct scrub_ctx
*ctx
)
295 char label
[FSLABEL_MAX
];
296 struct unicrash
*uc
= NULL
;
300 moveon
= unicrash_fs_label_init(&uc
, ctx
);
304 /* Retrieve label; quietly bail if we don't support that. */
305 error
= ioctl(ctx
->mnt
.fd
, FS_IOC_GETFSLABEL
, &label
);
307 if (errno
!= EOPNOTSUPP
&& errno
!= ENOTTY
) {
309 perror(ctx
->mntpoint
);
314 /* Ignore empty labels. */
318 /* Otherwise check for weirdness. */
320 moveon
= unicrash_check_fs_label(uc
, ctx
->mntpoint
, label
);
322 moveon
= xfs_scrub_check_name(ctx
, ctx
->mntpoint
,
323 _("filesystem label"), label
);
331 /* Check directory connectivity. */
333 xfs_scan_connections(
334 struct scrub_ctx
*ctx
)
339 if (ctx
->corruptions_found
|| ctx
->unfixable_errors
) {
340 str_info(ctx
, ctx
->mntpoint
,
341 _("Filesystem has errors, skipping connectivity checks."));
345 moveon
= xfs_scrub_fs_label(ctx
);
349 ret
= xfs_scan_all_inodes(ctx
, xfs_scrub_connections
, &moveon
);
354 xfs_scrub_report_preen_triggers(ctx
);