typedef struct SysAttrCacheEntry {
char *key;
char *value;
+ char *value_stripped;
+ size_t size;
int error;
} SysAttrCacheEntry;
free(p->key);
free(p->value);
+ free(p->value_stripped);
return mfree(p);
}
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);
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,
};
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);
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;
}
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;
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;
}
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:
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,
}
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) {
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);