2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2015-04-01 13:50:31 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#define FOREACH_DEVICE_PROPERTY(device, key, value) \
|
|
|
|
for (key = sd_device_get_property_first(device, &(value)); \
|
|
|
|
key; \
|
|
|
|
key = sd_device_get_property_next(device, &(value)))
|
|
|
|
|
|
|
|
#define FOREACH_DEVICE_TAG(device, tag) \
|
|
|
|
for (tag = sd_device_get_tag_first(device); \
|
|
|
|
tag; \
|
|
|
|
tag = sd_device_get_tag_next(device))
|
|
|
|
|
udev: make tags "sticky"
This tries to address the "bind"/"unbind" uevent kernel API breakage, by
changing the semantics of device tags.
Previously, tags would be applied on uevents (and the database entries
they result in) only depending on the immediate context. This means that
if one uevent causes the tag to be set and the next to be unset, this
would immediately effect what apps would see and the database entries
would contain each time. This is problematic however, as tags are a
filtering concept, and if tags vanish then clients won't hence notice
when a device stops being relevant to them since not only the tags
disappear but immediately also the uevents for it are filtered including
the one necessary for the app to notice that the device lost its tag and
hence relevance.
With this change tags become "sticky". If a tag is applied is once
applied to a device it will stay in place forever, until the device is
removed. Tags can never be removed again. This means that an app
watching a specific set of devices by filtering for a tag is guaranteed
to not only see the events where the tag is set but also all follow-up
events where the tags might be removed again.
This change of behaviour is unfortunate, but is required due to the
kernel introducing new "bind" and "unbind" uevents that generally have
the effect that tags and properties disappear and apps hence don't
notice when a device looses relevance to it. "bind"/"unbind" events were
introduced in kernel 4.12, and are now used in more and more subsystems.
The introduction broke userspace widely, and this commit is an attempt
to provide a way for apps to deal with it.
While tags are now "sticky" a new automatic device property
CURRENT_TAGS is introduced (matching the existing TAGS property) that
always reflects the precise set of tags applied on the most recent
events. Thus, when subscribing to devices through tags, all devices that
ever had the tag put on them will be be seen, and by CURRENT_TAGS it may
be checked whether the device right at the moment matches the tag
requirements.
See: #7587 #7018 #8221
2018-12-13 17:55:14 +01:00
|
|
|
#define FOREACH_DEVICE_CURRENT_TAG(device, tag) \
|
|
|
|
for (tag = sd_device_get_current_tag_first(device); \
|
|
|
|
tag; \
|
|
|
|
tag = sd_device_get_current_tag_next(device))
|
|
|
|
|
2015-04-01 13:50:31 +02:00
|
|
|
#define FOREACH_DEVICE_SYSATTR(device, attr) \
|
|
|
|
for (attr = sd_device_get_sysattr_first(device); \
|
|
|
|
attr; \
|
|
|
|
attr = sd_device_get_sysattr_next(device))
|
|
|
|
|
|
|
|
#define FOREACH_DEVICE_DEVLINK(device, devlink) \
|
|
|
|
for (devlink = sd_device_get_devlink_first(device); \
|
|
|
|
devlink; \
|
|
|
|
devlink = sd_device_get_devlink_next(device))
|
2015-04-14 16:22:39 +02:00
|
|
|
|
|
|
|
#define FOREACH_DEVICE(enumerator, device) \
|
|
|
|
for (device = sd_device_enumerator_get_device_first(enumerator); \
|
|
|
|
device; \
|
|
|
|
device = sd_device_enumerator_get_device_next(enumerator))
|
|
|
|
|
|
|
|
#define FOREACH_SUBSYSTEM(enumerator, device) \
|
|
|
|
for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
|
|
|
|
device; \
|
|
|
|
device = sd_device_enumerator_get_subsystem_next(enumerator))
|
2018-10-22 05:04:13 +02:00
|
|
|
|
|
|
|
#define log_device_full(device, level, error, ...) \
|
|
|
|
({ \
|
2018-11-01 08:12:46 +01:00
|
|
|
const char *_sysname = NULL; \
|
2018-10-22 05:04:13 +02:00
|
|
|
sd_device *_d = (device); \
|
|
|
|
int _level = (level), _error = (error); \
|
|
|
|
\
|
2020-07-16 16:23:57 +02:00
|
|
|
if (_d && _unlikely_(log_get_max_level() >= LOG_PRI(_level))) \
|
2018-10-22 05:04:13 +02:00
|
|
|
(void) sd_device_get_sysname(_d, &_sysname); \
|
2019-06-07 15:00:47 +02:00
|
|
|
log_object_internal(_level, _error, PROJECT_FILE, __LINE__, __func__, \
|
2018-10-22 05:04:13 +02:00
|
|
|
_sysname ? "DEVICE=" : NULL, _sysname, \
|
2018-11-01 08:12:46 +01:00
|
|
|
NULL, NULL, ##__VA_ARGS__); \
|
2018-10-22 05:04:13 +02:00
|
|
|
})
|
|
|
|
|
2018-10-23 19:46:41 +02:00
|
|
|
#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, 0, ##__VA_ARGS__)
|
|
|
|
#define log_device_info(device, ...) log_device_full(device, LOG_INFO, 0, ##__VA_ARGS__)
|
|
|
|
#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, 0, ##__VA_ARGS__)
|
|
|
|
#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, 0, ##__VA_ARGS__)
|
|
|
|
#define log_device_error(device, ...) log_device_full(device, LOG_ERR, 0, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
#define log_device_debug_errno(device, error, ...) log_device_full(device, LOG_DEBUG, error, ##__VA_ARGS__)
|
|
|
|
#define log_device_info_errno(device, error, ...) log_device_full(device, LOG_INFO, error, ##__VA_ARGS__)
|
|
|
|
#define log_device_notice_errno(device, error, ...) log_device_full(device, LOG_NOTICE, error, ##__VA_ARGS__)
|
|
|
|
#define log_device_warning_errno(device, error, ...) log_device_full(device, LOG_WARNING, error, ##__VA_ARGS__)
|
|
|
|
#define log_device_error_errno(device, error, ...) log_device_full(device, LOG_ERR, error, ##__VA_ARGS__)
|