}
_DEFINE_ABS_WRAPPER(DEVICE_ABSENT_OR_EMPTY);
-/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and
- * where it simply doesn't have the requested xattr the same way */
+/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all,
+ * where the path component carrying the xattr is missing, and where it simply doesn't have the requested
+ * xattr the same way. Note that getxattr(2) does not enumerate -ENOENT in its own error list, but inherits
+ * it via stat(2) (see ERRORS in getxattr(2)) for the path-component-missing case. */
static inline bool ERRNO_IS_NEG_XATTR_ABSENT(intmax_t r) {
return r == -ENODATA ||
+ r == -ENOENT ||
ERRNO_IS_NEG_NOT_SUPPORTED(r);
}
_DEFINE_ABS_WRAPPER(XATTR_ABSENT);
if (r < 0) {
_cleanup_free_ char *p = NULL;
- if (r != -ENOENT && !ERRNO_IS_XATTR_ABSENT(r))
+ if (!ERRNO_IS_XATTR_ABSENT(r))
return r;
p = build_auxiliary_path(image, ".roothash");
if (r < 0) {
_cleanup_free_ char *p = NULL;
- if (r != -ENOENT && !ERRNO_IS_XATTR_ABSENT(r))
+ if (!ERRNO_IS_XATTR_ABSENT(r))
return r;
p = build_auxiliary_path(image, ".usrhash");
r = getxattr_at_malloc(fd, "usr", "user.idontexist", 0, &value, /* ret_size= */ NULL);
ASSERT_TRUE(ERRNO_IS_NEG_XATTR_ABSENT(r));
+ /* A non-existent path component must also be treated as xattr-absent. The kernel
+ * returns -ENOENT in this case, which is inherited from stat(2)'s error list
+ * (see ERRORS in getxattr(2)). Without this, callers that semantically just want
+ * to know "is the xattr there?" end up logging spurious errors for paths that
+ * are simply gone — e.g. journald reading a unit's cgroup xattr after the
+ * cgroup directory has been torn down. */
+ r = getxattr_at_malloc(fd, "this-path-does-not-exist-XXXXXX", "user.idontexist",
+ 0, &value, /* ret_size= */ NULL);
+ ASSERT_TRUE(ERRNO_IS_NEG_XATTR_ABSENT(r));
+
safe_close(fd);
ASSERT_OK_ERRNO(fd = open(x, O_PATH|O_CLOEXEC));
ASSERT_OK(getxattr_at_malloc(fd, NULL, "user.foo", 0, &value, /* ret_size= */ NULL));