]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase5.c
2 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <sys/types.h>
24 #include <sys/statvfs.h>
26 # include <attr/attributes.h>
31 #include "workqueue.h"
32 #include "xfs_scrub.h"
39 /* Phase 5: Check directory connectivity. */
42 * Warn about problematic bytes in a directory/attribute name. That means
43 * terminal control characters and escape sequences, since that could be used
44 * to do something naughty to the user's computer and/or break scripts. XFS
45 * doesn't consider any byte sequence invalid, so don't flag these as errors.
49 struct scrub_ctx
*ctx
,
51 const char *namedescr
,
58 /* Complain about zero length names. */
59 if (*name
== '\0' && should_warn_about_name(ctx
)) {
60 str_warn(ctx
, descr
, _("Zero length name found."));
64 /* control characters */
65 for (p
= name
; *p
; p
++) {
66 if ((*p
>= 1 && *p
<= 31) || *p
== 127) {
72 if (bad
&& should_warn_about_name(ctx
)) {
73 errname
= string_escape(name
);
75 str_errno(ctx
, descr
);
79 _("Control character found in %s name \"%s\"."),
88 * Iterate a directory looking for filenames with problematic
92 xfs_scrub_scan_dirents(
93 struct scrub_ctx
*ctx
,
96 struct xfs_bstat
*bstat
)
98 struct unicrash
*uc
= NULL
;
100 struct dirent
*dentry
;
103 dir
= fdopendir(*fd
);
105 str_errno(ctx
, descr
);
108 *fd
= -1; /* closedir will close *fd for us */
110 moveon
= unicrash_dir_init(&uc
, ctx
, bstat
);
114 dentry
= readdir(dir
);
116 moveon
= xfs_scrub_check_name(ctx
, descr
, _("directory"),
120 moveon
= unicrash_check_dir_name(uc
, descr
, dentry
);
123 dentry
= readdir(dir
);
134 /* Routines to scan all of an inode's xattrs for name problems. */
140 static const struct xfs_attr_ns attr_ns
[] = {
142 {ATTR_ROOT
, "system"},
143 {ATTR_SECURE
, "secure"},
148 * Check all the xattr names in a particular namespace of a file handle
149 * for Unicode normalization problems or collisions.
152 xfs_scrub_scan_fhandle_namespace_xattrs(
153 struct scrub_ctx
*ctx
,
155 struct xfs_handle
*handle
,
156 struct xfs_bstat
*bstat
,
157 const struct xfs_attr_ns
*attr_ns
)
159 struct attrlist_cursor cur
;
160 char attrbuf
[XFS_XATTR_LIST_MAX
];
161 char keybuf
[NAME_MAX
+ 1];
162 struct attrlist
*attrlist
= (struct attrlist
*)attrbuf
;
163 struct attrlist_ent
*ent
;
169 moveon
= unicrash_xattr_init(&uc
, ctx
, bstat
);
173 memset(attrbuf
, 0, XFS_XATTR_LIST_MAX
);
174 memset(&cur
, 0, sizeof(cur
));
175 memset(keybuf
, 0, 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
, NAME_MAX
, "%s.%s", attr_ns
->name
,
184 moveon
= xfs_scrub_check_name(ctx
, descr
,
185 _("extended attribute"), keybuf
);
188 moveon
= unicrash_check_xattr_name(uc
, descr
, keybuf
);
193 if (!attrlist
->al_more
)
195 error
= attr_list_by_handle(handle
, sizeof(*handle
), attrbuf
,
196 XFS_XATTR_LIST_MAX
, attr_ns
->flags
, &cur
);
198 if (error
&& errno
!= ESTALE
)
199 str_errno(ctx
, descr
);
206 * Check all the xattr names in all the xattr namespaces for problematic
210 xfs_scrub_scan_fhandle_xattrs(
211 struct scrub_ctx
*ctx
,
213 struct xfs_handle
*handle
,
214 struct xfs_bstat
*bstat
)
216 const struct xfs_attr_ns
*ns
;
219 for (ns
= attr_ns
; ns
->name
; ns
++) {
220 moveon
= xfs_scrub_scan_fhandle_namespace_xattrs(ctx
, descr
,
228 # define xfs_scrub_scan_fhandle_xattrs(c, d, h, b) (true)
229 #endif /* HAVE_LIBATTR */
232 * Verify the connectivity of the directory tree.
233 * We know that the kernel's open-by-handle function will try to reconnect
234 * parents of an opened directory, so we'll accept that as sufficient.
236 * Check for potential Unicode collisions in names.
239 xfs_scrub_connections(
240 struct scrub_ctx
*ctx
,
241 struct xfs_handle
*handle
,
242 struct xfs_bstat
*bstat
,
246 char descr
[DESCR_BUFSZ
];
252 agno
= bstat
->bs_ino
/ (1ULL << (ctx
->inopblog
+ ctx
->agblklog
));
253 agino
= bstat
->bs_ino
% (1ULL << (ctx
->inopblog
+ ctx
->agblklog
));
254 snprintf(descr
, DESCR_BUFSZ
, _("inode %"PRIu64
" (%u/%u)"),
255 (uint64_t)bstat
->bs_ino
, agno
, agino
);
258 /* Warn about naming problems in xattrs. */
259 moveon
= xfs_scrub_scan_fhandle_xattrs(ctx
, descr
, handle
, bstat
);
263 /* Open the dir, let the kernel try to reconnect it to the root. */
264 if (S_ISDIR(bstat
->bs_mode
)) {
265 fd
= xfs_open_handle(handle
);
269 str_errno(ctx
, descr
);
274 /* Warn about naming problems in the directory entries. */
275 if (fd
>= 0 && S_ISDIR(bstat
->bs_mode
)) {
276 moveon
= xfs_scrub_scan_dirents(ctx
, descr
, &fd
, bstat
);
287 return *pmoveon
? 0 : XFS_ITERATE_INODES_ABORT
;
290 /* Check directory connectivity. */
292 xfs_scan_connections(
293 struct scrub_ctx
*ctx
)
298 if (ctx
->errors_found
) {
299 str_info(ctx
, ctx
->mntpoint
,
300 _("Filesystem has errors, skipping connectivity checks."));
304 ret
= xfs_scan_all_inodes(ctx
, xfs_scrub_connections
, &moveon
);
309 xfs_scrub_report_preen_triggers(ctx
);