if (size == SIZE_MAX)
size = strlen(value);
+ /* Skip the write if the xattr already has the correct value, to avoid
+ * unnecessary timestamp changes on the file. Only do this for plain
+ * replace mode (xattr_flags == 0) — XATTR_CREATE callers expect
+ * -EEXIST when the xattr already exists. */
+ _cleanup_free_ char *old_value = NULL;
+ size_t old_size;
+
+ if (xattr_flags == 0 &&
+ getxattr_at_malloc(fd, path, name, at_flags, &old_value, &old_size) >= 0 &&
+ memcmp_nn(old_value, old_size, value, size) == 0)
+ return 0;
+
if (have_xattrat && !isempty(path)) {
struct xattr_args args = {
.value = PTR_TO_UINT64(value),
}
#if HAVE_SELINUX
+static int setfilecon_idempotent(int fd, const char *context) {
+ _cleanup_freecon_ char *oldcon = NULL;
+
+ assert(fd >= 0);
+ assert(context);
+
+ /* Read current context via /proc/self/fd/ so this works for O_PATH fds too */
+ if (sym_getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(context, oldcon))
+ return 0; /* Already correct */
+
+ return RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), context));
+}
+
static int selinux_fix_fd(
int fd,
const char *label_path,
return log_selinux_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path);
}
- r = RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon));
- if (r < 0) {
- /* If the FS doesn't support labels, then exit without warning */
- if (ERRNO_IS_NOT_SUPPORTED(r))
- return 0;
-
- /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
- if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
- return 0;
+ r = setfilecon_idempotent(fd, fcon);
+ if (r >= 0)
+ return 0;
- /* If the old label is identical to the new one, suppress any kind of error */
- _cleanup_freecon_ char *oldcon = NULL;
- if (sym_getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(fcon, oldcon))
- return 0;
+ /* If the FS doesn't support labels, then exit without warning */
+ if (ERRNO_IS_NOT_SUPPORTED(r))
+ return 0;
- return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
- }
+ /* If the FS is read-only and we were told to ignore failures caused by that, suppress error */
+ if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
+ return 0;
- return 0;
+ return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
}
#endif
assert(label);
- if (sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), label) < 0)
- return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
+ r = setfilecon_idempotent(fd, label);
+ if (r < 0)
+ return log_selinux_enforcing_errno(r, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
#endif
return 0;
}
to ignore failures caused by that,
suppress error */
return 0;
- if (r < 0) {
- /* If the old label is identical to the new one, suppress any kind of error */
- _cleanup_free_ char *old_label = NULL;
-
- if (fgetxattr_malloc(fd, "security.SMACK64", &old_label, /* ret_size= */ NULL) >= 0 &&
- streq(old_label, label))
- return 0;
-
+ if (r < 0)
return log_debug_errno(r, "Unable to fix SMACK label of '%s': %m", label_path);
- }
return 0;
}