mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #24731 from yuwata/sd-device-opendir
sd-device: introduce device_opendir()
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -14,6 +15,8 @@ int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum);
|
||||
int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len);
|
||||
int device_new_from_strv(sd_device **ret, char **strv);
|
||||
|
||||
int device_opendir(sd_device *device, const char *subdir, DIR **ret);
|
||||
|
||||
int device_get_property_bool(sd_device *device, const char *key);
|
||||
int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
|
||||
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
|
||||
|
||||
@@ -1866,42 +1866,32 @@ _public_ const char *sd_device_get_property_next(sd_device *device, const char *
|
||||
return key;
|
||||
}
|
||||
|
||||
static int device_sysattrs_read_all_internal(sd_device *device, const char *subdir) {
|
||||
_cleanup_free_ char *path_dir = NULL;
|
||||
static int device_sysattrs_read_all_internal(sd_device *device, const char *subdir, Set **stack) {
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
const char *syspath;
|
||||
int r;
|
||||
|
||||
r = sd_device_get_syspath(device, &syspath);
|
||||
assert(device);
|
||||
assert(stack);
|
||||
|
||||
r = device_opendir(device, subdir, &dir);
|
||||
if (r == -ENOENT && subdir)
|
||||
return 0; /* Maybe, this is a child device, and is already removed. */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (subdir) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = path_join(syspath, subdir, "uevent");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (access(p, F_OK) >= 0)
|
||||
/* this is a child device, skipping */
|
||||
return 0;
|
||||
if (faccessat(dirfd(dir), "uevent", F_OK, 0) >= 0)
|
||||
return 0; /* this is a child device, skipping */
|
||||
if (errno != ENOENT) {
|
||||
log_device_debug_errno(device, errno, "sd-device: Failed to stat %s, ignoring subdir: %m", p);
|
||||
log_device_debug_errno(device, errno,
|
||||
"sd-device: Failed to access %s/uevent, ignoring sub-directory %s: %m",
|
||||
subdir, subdir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path_dir = path_join(syspath, subdir);
|
||||
if (!path_dir)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dir = opendir(path_dir ?: syspath);
|
||||
if (!dir)
|
||||
return -errno;
|
||||
|
||||
FOREACH_DIRENT_ALL(de, dir, return -errno) {
|
||||
_cleanup_free_ char *path = NULL, *p = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
struct stat statbuf;
|
||||
|
||||
if (dot_or_dot_dot(de->d_name))
|
||||
@@ -1918,25 +1908,27 @@ static int device_sysattrs_read_all_internal(sd_device *device, const char *subd
|
||||
}
|
||||
|
||||
if (de->d_type == DT_DIR) {
|
||||
/* read subdirectory */
|
||||
r = device_sysattrs_read_all_internal(device, p ?: de->d_name);
|
||||
/* push the sub-directory into the stack, and read it later. */
|
||||
if (p)
|
||||
r = set_ensure_consume(stack, &path_hash_ops_free, TAKE_PTR(p));
|
||||
else
|
||||
r = set_put_strdup_full(stack, &path_hash_ops_free, de->d_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
path = path_join(syspath, p ?: de->d_name);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (lstat(path, &statbuf) != 0)
|
||||
if (fstatat(dirfd(dir), de->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
continue;
|
||||
|
||||
if ((statbuf.st_mode & (S_IRUSR | S_IWUSR)) == 0)
|
||||
continue;
|
||||
|
||||
r = set_put_strdup(&device->sysattrs, p ?: de->d_name);
|
||||
if (p)
|
||||
r = set_ensure_consume(&device->sysattrs, &path_hash_ops_free, TAKE_PTR(p));
|
||||
else
|
||||
r = set_put_strdup_full(&device->sysattrs, &path_hash_ops_free, de->d_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -1945,6 +1937,7 @@ static int device_sysattrs_read_all_internal(sd_device *device, const char *subd
|
||||
}
|
||||
|
||||
static int device_sysattrs_read_all(sd_device *device) {
|
||||
_cleanup_set_free_ Set *stack = NULL;
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
@@ -1952,10 +1945,22 @@ static int device_sysattrs_read_all(sd_device *device) {
|
||||
if (device->sysattrs_read)
|
||||
return 0;
|
||||
|
||||
r = device_sysattrs_read_all_internal(device, NULL);
|
||||
r = device_sysattrs_read_all_internal(device, NULL, &stack);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *subdir = NULL;
|
||||
|
||||
subdir = set_steal_first(stack);
|
||||
if (!subdir)
|
||||
break;
|
||||
|
||||
r = device_sysattrs_read_all_internal(device, subdir, &stack);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
device->sysattrs_read = true;
|
||||
|
||||
return 0;
|
||||
@@ -2453,3 +2458,33 @@ _public_ int sd_device_open(sd_device *device, int flags) {
|
||||
|
||||
return TAKE_FD(fd2);
|
||||
}
|
||||
|
||||
int device_opendir(sd_device *device, const char *subdir, DIR **ret) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
const char *syspath;
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
assert(ret);
|
||||
|
||||
r = sd_device_get_syspath(device, &syspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (subdir) {
|
||||
if (!path_is_safe(subdir))
|
||||
return -EINVAL;
|
||||
|
||||
path = path_join(syspath, subdir);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
d = opendir(path ?: syspath);
|
||||
if (!d)
|
||||
return -errno;
|
||||
|
||||
*ret = TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase-symlinks.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
@@ -98,7 +99,7 @@ static sd_device *skip_virtio(sd_device *dev) {
|
||||
|
||||
static int get_virtfn_info(sd_device *pcidev, sd_device **ret_physfn_pcidev, char **ret_suffix) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL;
|
||||
const char *physfn_syspath, *syspath;
|
||||
const char *syspath;
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
int r;
|
||||
|
||||
@@ -115,15 +116,11 @@ static int get_virtfn_info(sd_device *pcidev, sd_device **ret_physfn_pcidev, cha
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_syspath(physfn_pcidev, &physfn_syspath);
|
||||
/* Find the virtual function number by finding the right virtfn link. */
|
||||
r = device_opendir(physfn_pcidev, NULL, &dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Find the virtual function number by finding the right virtfn link. */
|
||||
dir = opendir(physfn_syspath);
|
||||
if (!dir)
|
||||
return -errno;
|
||||
|
||||
FOREACH_DIRENT_ALL(de, dir, break) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *virtfn_pcidev = NULL;
|
||||
const char *n, *s;
|
||||
@@ -285,9 +282,9 @@ static bool is_pci_bridge(sd_device *dev) {
|
||||
return b;
|
||||
}
|
||||
|
||||
static int parse_hotplug_slot_from_function_id(sd_device *dev, const char *slots, uint32_t *ret) {
|
||||
static int parse_hotplug_slot_from_function_id(sd_device *dev, int slots_dirfd, uint32_t *ret) {
|
||||
uint64_t function_id;
|
||||
char path[PATH_MAX];
|
||||
char filename[NAME_MAX+1];
|
||||
const char *attr;
|
||||
int r;
|
||||
|
||||
@@ -300,7 +297,7 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, const char *slots
|
||||
* between PCI function and its hotplug slot. */
|
||||
|
||||
assert(dev);
|
||||
assert(slots);
|
||||
assert(slots_dirfd >= 0);
|
||||
assert(ret);
|
||||
|
||||
if (!naming_scheme_has(NAMING_SLOT_FUNCTION_ID))
|
||||
@@ -318,27 +315,27 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, const char *slots
|
||||
"Invalid function id (0x%"PRIx64"), ignoring.",
|
||||
function_id);
|
||||
|
||||
if (!snprintf_ok(path, sizeof path, "%s/%08"PRIx64, slots, function_id))
|
||||
if (!snprintf_ok(filename, sizeof(filename), "%08"PRIx64, function_id))
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENAMETOOLONG),
|
||||
"PCI slot path is too long, ignoring.");
|
||||
|
||||
if (access(path, F_OK) < 0)
|
||||
return log_device_debug_errno(dev, errno, "Cannot access %s, ignoring: %m", path);
|
||||
if (faccessat(slots_dirfd, filename, F_OK, 0) < 0)
|
||||
return log_device_debug_errno(dev, errno, "Cannot access %s under pci slots, ignoring: %m", filename);
|
||||
|
||||
*ret = (uint32_t) function_id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
||||
const char *sysname, *attr, *syspath;
|
||||
const char *sysname, *attr;
|
||||
_cleanup_(sd_device_unrefp) sd_device *pci = NULL;
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
unsigned domain, bus, slot, func;
|
||||
sd_device *hotplug_slot_dev;
|
||||
unsigned long dev_port = 0;
|
||||
uint32_t hotplug_slot = 0;
|
||||
char slots[PATH_MAX], *s;
|
||||
size_t l;
|
||||
char *s;
|
||||
int r;
|
||||
|
||||
assert(dev);
|
||||
@@ -409,21 +406,13 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "sd_device_new_from_subsystem_sysname() failed: %m");
|
||||
|
||||
r = sd_device_get_syspath(pci, &syspath);
|
||||
r = device_opendir(pci, "slots", &dir);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(pci, r, "sd_device_get_syspath() failed: %m");
|
||||
|
||||
if (!snprintf_ok(slots, sizeof slots, "%s/slots", syspath))
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENAMETOOLONG),
|
||||
"Cannot access %s/slots: %m", syspath);
|
||||
|
||||
dir = opendir(slots);
|
||||
if (!dir)
|
||||
return log_device_debug_errno(dev, errno, "Cannot access %s: %m", slots);
|
||||
return log_device_debug_errno(dev, r, "Cannot access 'slots' subdirectory: %m");
|
||||
|
||||
hotplug_slot_dev = names->pcidev;
|
||||
while (hotplug_slot_dev) {
|
||||
r = parse_hotplug_slot_from_function_id(hotplug_slot_dev, slots, &hotplug_slot);
|
||||
r = parse_hotplug_slot_from_function_id(hotplug_slot_dev, dirfd(dir), &hotplug_slot);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
if (r > 0) {
|
||||
@@ -436,8 +425,8 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
||||
return log_device_debug_errno(hotplug_slot_dev, r, "Failed to get sysname: %m");
|
||||
|
||||
FOREACH_DIRENT_ALL(de, dir, break) {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
char str[PATH_MAX];
|
||||
_cleanup_free_ char *path = NULL;
|
||||
const char *address;
|
||||
uint32_t i;
|
||||
|
||||
if (dot_or_dot_dot(de->d_name))
|
||||
@@ -447,30 +436,37 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
||||
if (r < 0 || i <= 0)
|
||||
continue;
|
||||
|
||||
path = path_join("slots", de->d_name, "address");
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sd_device_get_sysattr_value(pci, path, &address) < 0)
|
||||
continue;
|
||||
|
||||
/* match slot address with device by stripping the function */
|
||||
if (snprintf_ok(str, sizeof str, "%s/%s/address", slots, de->d_name) &&
|
||||
read_one_line_file(str, &address) >= 0 &&
|
||||
startswith(sysname, address)) {
|
||||
hotplug_slot = i;
|
||||
if (!startswith(sysname, address))
|
||||
continue;
|
||||
|
||||
/* We found the match between PCI device and slot. However, we won't use the
|
||||
* slot index if the device is a PCI bridge, because it can have other child
|
||||
* devices that will try to claim the same index and that would create name
|
||||
* collision. */
|
||||
if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
|
||||
if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(names->pcidev) <= 0) {
|
||||
log_device_debug(dev, "Not using slot information because the PCI device associated with the hotplug slot is a bridge and the PCI device has single function.");
|
||||
return 0;
|
||||
}
|
||||
hotplug_slot = i;
|
||||
|
||||
if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
|
||||
log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
|
||||
return 0;
|
||||
}
|
||||
/* We found the match between PCI device and slot. However, we won't use the slot
|
||||
* index if the device is a PCI bridge, because it can have other child devices that
|
||||
* will try to claim the same index and that would create name collision. */
|
||||
if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
|
||||
if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(names->pcidev) <= 0) {
|
||||
log_device_debug(dev,
|
||||
"Not using slot information because the PCI device associated with "
|
||||
"the hotplug slot is a bridge and the PCI device has a single function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
|
||||
log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (hotplug_slot > 0)
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user