sd-device: Introduce sd_device_get_sysattr_value_with_size()
This commit is contained in:
@@ -1064,6 +1064,7 @@ LIBSYSTEMD_258 {
|
||||
global:
|
||||
sd_bus_message_dump_json;
|
||||
sd_device_enumerator_add_all_parents;
|
||||
sd_device_get_sysattr_value_with_size;
|
||||
sd_json_variant_type_from_string;
|
||||
sd_json_variant_type_to_string;
|
||||
sd_varlink_get_current_method;
|
||||
|
||||
@@ -2333,6 +2333,8 @@ void device_clear_sysattr_cache(sd_device *device) {
|
||||
typedef struct SysAttrCacheEntry {
|
||||
char *key;
|
||||
char *value;
|
||||
char *value_stripped;
|
||||
size_t size;
|
||||
int error;
|
||||
} SysAttrCacheEntry;
|
||||
|
||||
@@ -2342,6 +2344,7 @@ static SysAttrCacheEntry* sysattr_cache_entry_free(SysAttrCacheEntry *p) {
|
||||
|
||||
free(p->key);
|
||||
free(p->value);
|
||||
free(p->value_stripped);
|
||||
return mfree(p);
|
||||
}
|
||||
|
||||
@@ -2350,7 +2353,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
char, path_hash_func, path_compare,
|
||||
SysAttrCacheEntry, sysattr_cache_entry_free);
|
||||
|
||||
static int device_cache_sysattr_value_full(sd_device *device, char *key, char *value, int error, bool ignore_uevent) {
|
||||
static int device_cache_sysattr_value_full(sd_device *device, char *key, char *value, size_t size, int error, bool ignore_uevent) {
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
@@ -2375,9 +2378,20 @@ static int device_cache_sysattr_value_full(sd_device *device, char *key, char *v
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
_cleanup_free_ char *value_stripped = NULL;
|
||||
|
||||
if (value) {
|
||||
value_stripped = memdup_suffix0(value, size);
|
||||
if (!value_stripped)
|
||||
return -ENOMEM;
|
||||
delete_trailing_chars(value_stripped, NEWLINE);
|
||||
}
|
||||
|
||||
*entry = (SysAttrCacheEntry) {
|
||||
.key = key,
|
||||
.value = value,
|
||||
.value_stripped = value_stripped,
|
||||
.size = size,
|
||||
.error = error,
|
||||
};
|
||||
|
||||
@@ -2386,14 +2400,15 @@ static int device_cache_sysattr_value_full(sd_device *device, char *key, char *v
|
||||
return r;
|
||||
|
||||
TAKE_PTR(entry);
|
||||
TAKE_PTR(value_stripped);
|
||||
return 1; /* cached */
|
||||
}
|
||||
|
||||
int device_cache_sysattr_value(sd_device *device, char *key, char *value, int error) {
|
||||
return device_cache_sysattr_value_full(device, key, value, error, /* ignore_uevent = */ true);
|
||||
return device_cache_sysattr_value_full(device, key, value, strlen(value), error, /* ignore_uevent = */ true);
|
||||
}
|
||||
|
||||
static int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) {
|
||||
static int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value, size_t *ret_size) {
|
||||
SysAttrCacheEntry *entry;
|
||||
|
||||
assert(device);
|
||||
@@ -2408,7 +2423,9 @@ static int device_get_cached_sysattr_value(sd_device *device, const char *key, c
|
||||
return -entry->error;
|
||||
}
|
||||
if (ret_value)
|
||||
*ret_value = entry->value;
|
||||
*ret_value = ret_size ? entry->value : entry->value_stripped;
|
||||
if (ret_size)
|
||||
*ret_size = entry->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2459,16 +2476,17 @@ int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **r
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
|
||||
_public_ int sd_device_get_sysattr_value_with_size(sd_device *device, const char *sysattr, const char **ret_value, size_t *ret_size) {
|
||||
_cleanup_free_ char *resolved = NULL, *value = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
size_t size = 0;
|
||||
int r;
|
||||
|
||||
assert_return(device, -EINVAL);
|
||||
assert_return(sysattr, -EINVAL);
|
||||
|
||||
/* Look for possibly already cached result. */
|
||||
r = device_get_cached_sysattr_value(device, sysattr, ret_value);
|
||||
r = device_get_cached_sysattr_value(device, sysattr, ret_value, ret_size);
|
||||
if (r != -ENOANO)
|
||||
return r;
|
||||
|
||||
@@ -2487,6 +2505,9 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
|
||||
return -ENOMEM;
|
||||
|
||||
r = readlink_value(prefixed, &value);
|
||||
if (r >= 0)
|
||||
size = strlen(value);
|
||||
|
||||
if (r != -EINVAL) /* -EINVAL means the path is not a symlink. */
|
||||
goto cache_result;
|
||||
}
|
||||
@@ -2496,18 +2517,16 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
|
||||
goto cache_result;
|
||||
|
||||
/* Look for cached result again with the resolved path. */
|
||||
r = device_get_cached_sysattr_value(device, resolved, ret_value);
|
||||
r = device_get_cached_sysattr_value(device, resolved, ret_value, ret_size);
|
||||
if (r != -ENOANO)
|
||||
return r;
|
||||
|
||||
/* Read attribute value, Some attributes contain embedded '\0'. So, it is necessary to also get the
|
||||
* size of the result. See issue #20025. */
|
||||
size_t size;
|
||||
r = read_virtual_file_fd(fd, SIZE_MAX, &value, &size);
|
||||
if (r < 0)
|
||||
goto cache_result;
|
||||
|
||||
delete_trailing_chars(value, NEWLINE);
|
||||
r = 0;
|
||||
|
||||
cache_result:
|
||||
@@ -2521,7 +2540,7 @@ cache_result:
|
||||
return RET_GATHER(r, -ENOMEM);
|
||||
}
|
||||
|
||||
int k = device_cache_sysattr_value_full(device, resolved, value, -r, /* ignore_uevent = */ false);
|
||||
int k = device_cache_sysattr_value_full(device, resolved, value, size, -r, /* ignore_uevent = */ false);
|
||||
if (k < 0) {
|
||||
if (r < 0)
|
||||
log_device_debug_errno(device, k,
|
||||
@@ -2541,13 +2560,18 @@ cache_result:
|
||||
}
|
||||
assert(k > 0);
|
||||
|
||||
if (ret_value && r >= 0)
|
||||
*ret_value = value;
|
||||
|
||||
/* device_cache_sysattr_value_full() takes 'resolved' and 'value' on success. */
|
||||
TAKE_PTR(resolved);
|
||||
sysattr = TAKE_PTR(resolved);
|
||||
TAKE_PTR(value);
|
||||
return r;
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return device_get_cached_sysattr_value(device, sysattr, ret_value, ret_size);
|
||||
}
|
||||
|
||||
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
|
||||
return sd_device_get_sysattr_value_with_size(device, sysattr, ret_value, NULL);
|
||||
}
|
||||
|
||||
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value) {
|
||||
|
||||
@@ -133,6 +133,18 @@ static void test_sd_device_one(sd_device *d) {
|
||||
ASSERT_ERROR(r, ENOENT);
|
||||
}
|
||||
|
||||
if (streq(subsystem, "drm")) {
|
||||
const char *edid_content;
|
||||
size_t edid_size = 0;
|
||||
|
||||
r = sd_device_get_sysattr_value_with_size(d, "edid", &edid_content, &edid_size);
|
||||
if (r < 0)
|
||||
ASSERT_ERROR(r, ENOENT);
|
||||
|
||||
/* at least 128 if monitor is connected, otherwise 0 */
|
||||
ASSERT_TRUE(edid_size == 0 || edid_size >= 128);
|
||||
}
|
||||
|
||||
is_block = streq_ptr(subsystem, "block");
|
||||
|
||||
r = sd_device_get_devname(d, &devname);
|
||||
|
||||
@@ -108,7 +108,8 @@ int sd_device_has_tag(sd_device *device, const char *tag);
|
||||
int sd_device_has_current_tag(sd_device *device, const char *tag);
|
||||
int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
|
||||
int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret);
|
||||
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
|
||||
int sd_device_get_sysattr_value_with_size(sd_device *device, const char *sysattr, const char **ret_value, size_t *ret_size);
|
||||
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value);
|
||||
|
||||
int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
|
||||
int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4);
|
||||
|
||||
Reference in New Issue
Block a user