#include "alloc-util.h"
#include "blkid-util.h"
+#include "btrfs-util.h"
#include "chase-symlinks.h"
#include "device-util.h"
#include "devnum-util.h"
#include "env-util.h"
#include "errno-util.h"
+#include "fd-util.h"
#include "find-esp.h"
#include "gpt.h"
#include "parse-util.h"
const char *v;
int r;
- r = device_path_make_major_minor(S_IFBLK, devid, &node);
+ r = devname_from_devnum(S_IFBLK, devid, &node);
if (r < 0)
- return log_error_errno(r, "Failed to format major/minor device path: %m");
+ return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
errno = 0;
b = blkid_new_probe_from_filename(node);
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0)
return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
- if (sd_id128_string_equal(v, GPT_ESP) <= 0)
+ if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
sd_id128_t *ret_uuid) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
- _cleanup_free_ char *node = NULL;
sd_id128_t uuid = SD_ID128_NULL;
uint64_t pstart = 0, psize = 0;
uint32_t part = 0;
- const char *v;
+ const char *node, *v;
int r;
- r = device_path_make_major_minor(S_IFBLK, devid, &node);
- if (r < 0)
- return log_error_errno(r, "Failed to format major/minor device path: %m");
-
r = sd_device_new_from_devnum(&d, 'b', devid);
if (r < 0)
return log_error_errno(r, "Failed to get device from device number: %m");
+ r = sd_device_get_devname(d, &node);
+ if (r < 0)
+ return log_device_error_errno(d, r, "Failed to get device node: %m");
+
r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
if (!streq(v, "vfat"))
- return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
- SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
- "File system \"%s\" is not FAT.", node );
+ return log_device_full_errno(d,
+ searching ? LOG_DEBUG : LOG_ERR,
+ SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+ "File system \"%s\" is not FAT.", node );
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_full_errno(d,
+ searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
+ searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
+ "Failed to get device property: %m");
if (!streq(v, "gpt"))
- return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
- SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
- "File system \"%s\" is not on a GPT partition table.", node);
+ return log_device_full_errno(d,
+ searching ? LOG_DEBUG : LOG_ERR,
+ SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+ "File system \"%s\" is not on a GPT partition table.", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
- if (sd_id128_string_equal(v, GPT_ESP) <= 0)
- return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
- SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
- "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
+ if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
+ return log_device_full_errno(d,
+ searching ? LOG_DEBUG : LOG_ERR,
+ SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+ "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
r = sd_id128_from_string(v, &uuid);
if (r < 0)
- return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
+ return log_device_error_errno(d, r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou32(v, &part);
if (r < 0)
- return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
+ return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_NUMBER field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou64(v, &pstart);
if (r < 0)
- return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
+ return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_OFFSET field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou64(v, &psize);
if (r < 0)
- return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
+ return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_SIZE field.");
if (ret_part)
*ret_part = part;
bool unprivileged_mode,
dev_t *ret_dev) {
- struct stat st, st2;
- const char *t2, *trigger;
+ _cleanup_close_ int fd = -EBADF;
+ STRUCT_NEW_STATX_DEFINE(sxa);
+ STRUCT_NEW_STATX_DEFINE(sxb);
int r;
+ /* Checks if the specified directory is at the root of its file system, and returns device
+ * major/minor of the device, if it is. */
+
assert(path);
- assert(ret_dev);
+
+ /* We are using O_PATH here, since that way we can operate on directory inodes we cannot look into,
+ * which is quite likely if we run unprivileged */
+ fd = open(path, O_CLOEXEC|O_DIRECTORY|O_PATH);
+ if (fd < 0)
+ return log_full_errno((searching && errno == ENOENT) ||
+ (unprivileged_mode && ERRNO_IS_PRIVILEGE(errno)) ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to open directory \"%s\": %m", path);
/* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
* directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
* before stat()ing */
- trigger = strjoina(path, "/trigger"); /* Filename doesn't matter... */
- (void) access(trigger, F_OK);
+ (void) faccessat(fd, "trigger", F_OK, AT_SYMLINK_NOFOLLOW); /* Filename doesn't matter... */
- if (stat(path, &st) < 0)
- return log_full_errno((searching && errno == ENOENT) ||
- (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
+ r = statx_fallback(fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa.sx);
+ if (r < 0)
+ return log_full_errno((unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR, r,
"Failed to determine block device node of \"%s\": %m", path);
- if (major(st.st_dev) == 0)
- return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
- SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
- "Block device node of \"%s\" is invalid.", path);
-
- if (path_equal(path, "/")) {
- /* Let's assume that the root directory of the OS is always the root of its file system
- * (which technically doesn't have to be the case, but it's close enough, and it's not easy
- * to be fully correct for it, since we can't look further up than the root dir easily.) */
- if (ret_dev)
- *ret_dev = st.st_dev;
+ assert(S_ISDIR(sxa.sx.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */
- return 0;
- }
+ if (FLAGS_SET(sxa.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
- t2 = strjoina(path, "/..");
- if (stat(t2, &st2) < 0) {
- if (errno != EACCES)
- r = -errno;
- else {
- _cleanup_free_ char *parent = NULL;
+ /* If we have STATX_ATTR_MOUNT_ROOT, we are happy, that's all we need. We operate under the
+ * assumption that a top of a mount point is also the top of the file system. (Which of
+ * course is strictly speaking not always true...) */
- /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
- * directly instead. It's not as good, due to symlinks and such, but we can't do
- * anything better here. */
-
- parent = dirname_malloc(path);
- if (!parent)
- return log_oom();
+ if (!FLAGS_SET(sxa.sx.stx_attributes, STATX_ATTR_MOUNT_ROOT))
+ return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+ SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+ "Directory \"%s\" is not the root of the file system.", path);
- r = RET_NERRNO(stat(parent, &st2));
- }
+ goto success;
+ }
+ /* Now let's look at the parent */
+ r = statx_fallback(fd, "..", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb.sx);
+ if (r < 0 && ERRNO_IS_PRIVILEGE(r)) {
+ _cleanup_free_ char *parent = NULL;
+
+ /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
+ * directly instead. It's not as good, due to symlinks and such, but we can't do anything
+ * better here.
+ *
+ * (In case you wonder where this fallback is useful: consider a classic Fedora setup with
+ * /boot/ being an ext4 partition and /boot/efi/ being the VFAT ESP. The latter is mounted
+ * inaccessible for regular users via the dmask= mount option. In that case as unprivileged
+ * user we can stat() /boot/efi/, and we can stat()/enumerate /boot/. But we cannot look into
+ * /boot/efi/, and in particular not use /boot/efi/../ – hence this work-around.) */
+
+ if (path_equal(path, "/"))
+ goto success;
+
+ r = path_extract_directory(path, &parent);
if (r < 0)
- return log_full_errno(unprivileged_mode && r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
- "Failed to determine block device node of parent of \"%s\": %m", path);
+ return log_error_errno(r, "Failed to extract parent path from '%s': %m", path);
+
+ r = statx_fallback(AT_FDCWD, parent, AT_SYMLINK_NOFOLLOW, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb.sx);
}
+ if (r < 0)
+ return log_full_errno(unprivileged_mode && ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_ERR, r,
+ "Failed to determine block device node of parent of \"%s\": %m", path);
+
+ if (statx_inode_same(&sxa.sx, &sxb.sx)) /* for the root dir inode nr for both inodes will be the same */
+ goto success;
- if (st.st_dev == st2.st_dev)
+ if (statx_mount_same(&sxa.nsx, &sxb.nsx))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"Directory \"%s\" is not the root of the file system.", path);
- if (ret_dev)
- *ret_dev = st.st_dev;
+success:
+ if (!ret_dev)
+ return 0;
+
+ if (sxa.sx.stx_dev_major == 0) { /* Hmm, maybe a btrfs device, and the caller asked for the backing device? Then let's try to get it. */
+ _cleanup_close_ int real_fd = -EBADF;
+
+ /* The statx() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. Hence
+ * acquire a "real" fd first, without the O_PATH flag. */
+
+ real_fd = fd_reopen(fd, O_DIRECTORY|O_CLOEXEC);
+ if (real_fd < 0)
+ return real_fd;
+ return btrfs_get_block_device_fd(real_fd, ret_dev);
+ }
+
+ *ret_dev = makedev(sxa.sx.stx_dev_major, sxa.sx.stx_dev_minor);
return 0;
}
bool relax_checks, searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE);
- dev_t devid;
+ dev_t devid = 0;
int r;
assert(p);
* -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
*/
- relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 || FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS);
+ relax_checks =
+ getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 ||
+ FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS);
/* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
* issues. Let's also, silence the error messages. */
"File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
}
- r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
+ relax_checks =
+ relax_checks ||
+ detect_container() > 0;
+
+ r = verify_fsroot_dir(p, searching, unprivileged_mode, relax_checks ? NULL : &devid);
if (r < 0)
return r;
/* In a container we don't have access to block devices, skip this part of the verification, we trust
* the container manager set everything up correctly on its own. */
- if (detect_container() > 0 || relax_checks)
+ if (relax_checks)
goto finish;
/* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
"Failed to resolve path %s%s%s: %m",
path,
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, flags);
if (r < 0)
"Failed to resolve path %s%s%s: %m",
path,
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
if (!path_is_valid(p) || !path_is_absolute(p))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to resolve path %s%s%s: %m",
dir,
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid,
flags | VERIFY_ESP_SEARCHING);
if (r >= 0)
goto found;
- if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
+ if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR)) /* This one is not it */
return r;
p = mfree(p);
const char *type, *v;
int r;
- r = device_path_make_major_minor(S_IFBLK, devid, &node);
+ r = devname_from_devnum(S_IFBLK, devid, &node);
if (r < 0)
- return log_error_errno(r, "Failed to format block device path for %u:%u: %m",
- major(devid), minor(devid));
+ return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m",
+ DEVNUM_FORMAT_VAL(devid));
errno = 0;
b = blkid_new_probe_from_filename(node);
if (!b)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "%s: Failed to create blkid probe: %m", node);
+ return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0;
r = blkid_do_safeprobe(b);
- if (r == -2)
+ if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
- else if (r == 1)
+ if (r == _BLKID_SAFEPROBE_NOT_FOUND)
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system does not contain a label.", node);
- else if (r != 0)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe file system: %m", node);
+ if (r == _BLKID_SAFEPROBE_ERROR)
+ return log_error_errno(errno_or_else(EIO), "%s: Failed to probe file system: %m", node);
+
+ assert(r == _BLKID_SAFEPROBE_FOUND);
- errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
if (r != 0)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
+ return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+ searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
+ "%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
if (streq(type, "gpt")) {
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
- if (sd_id128_string_equal(v, GPT_XBOOTLDR) <= 0)
+ return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
+ if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
"%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
if (r != 0)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
+ return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
r = sd_id128_from_string(v, &uuid);
if (r < 0)
return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0)
- return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
+ return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
if (!streq(v, "0xea"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
sd_id128_t *ret_uuid) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
- _cleanup_free_ char *node = NULL;
sd_id128_t uuid = SD_ID128_NULL;
- const char *type, *v;
+ const char *node, *type, *v;
int r;
- r = device_path_make_major_minor(S_IFBLK, devid, &node);
+ r = sd_device_new_from_devnum(&d, 'b', devid);
if (r < 0)
- return log_error_errno(r, "Failed to format block device path for %u:%u: %m",
- major(devid), minor(devid));
+ return log_error_errno(r, "Failed to get block device for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
- r = sd_device_new_from_devnum(&d, 'b', devid);
+ r = sd_device_get_devname(d, &node);
if (r < 0)
- return log_error_errno(r, "%s: Failed to get block device: %m", node);
+ return log_device_error_errno(d, r, "Failed to get device node: %m");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type);
if (r < 0)
- return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_SCHEME: %m");
+ return log_device_full_errno(d,
+ searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
+ searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
+ "Failed to query ID_PART_ENTRY_SCHEME: %m");
if (streq(type, "gpt")) {
if (r < 0)
return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
- r = sd_id128_string_equal(v, GPT_XBOOTLDR);
+ r = sd_id128_string_equal(v, SD_GPT_XBOOTLDR);
if (r < 0)
return log_device_error_errno(d, r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v);
if (r == 0)
dev_t *ret_devid) {
bool relax_checks;
- dev_t devid;
+ dev_t devid = 0;
int r;
assert(p);
- relax_checks = getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
+ relax_checks =
+ getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0 ||
+ detect_container() > 0;
- r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
+ r = verify_fsroot_dir(p, searching, unprivileged_mode, relax_checks ? NULL : &devid);
if (r < 0)
return r;
- if (detect_container() > 0 || relax_checks)
+ if (relax_checks)
goto finish;
if (unprivileged_mode)
"Failed to resolve path %s%s%s: %m",
path,
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
r = verify_xbootldr(p, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid);
if (r < 0)
"Failed to resolve path %s%s%s: %m",
path,
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
if (!path_is_valid(p) || !path_is_absolute(p))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return log_error_errno(r,
"Failed to resolve path /boot%s%s: %m",
root ? " under directory " : "",
- root ?: "");
+ strempty(root));
- r = verify_xbootldr(p, true, unprivileged_mode, ret_uuid, ret_devid);
+ r = verify_xbootldr(p, /* searching= */ true, unprivileged_mode, ret_uuid, ret_devid);
if (r >= 0)
goto found;
- if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
+ if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR)) /* This one is not it */
return r;
return -ENOKEY;