device-private.c revision aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_add_property(sd_device *device, const char *key, const char *value) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_add_property_aux(device, key, value, false);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_add_property_aux(device, key, value, true);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int device_add_property_internal_from_string(sd_device *device, const char *str) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return device_add_property_internal(device, key, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int handle_db_line(sd_device *device, char key, const char *value) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = safe_atoi(value, &device->devlink_priority);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_add_property_internal_from_string(device, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = safe_atoi(value, &device->watch_handle);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_set_usec_initialized(device, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_debug("device db: unknown key '%c'", key);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringvoid device_set_devlink_priority(sd_device *device, int priority) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringvoid device_set_is_initialized(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (device_old && device_old->usec_initialized > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering usec_initialized = device_old->usec_initialized;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_set_usec_initialized(device, num);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering /* devices with a database entry are initialized */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (i = 0; i < db_len; i++) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert_not_reached("invalid state when parsing db");
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringuint64_t device_get_properties_generation(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringuint64_t device_get_tags_generation(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringuint64_t device_get_devlinks_generation(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_devnode_mode(sd_device *device, mode_t *mode) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_devnode_uid(sd_device *device, uid_t *uid) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int device_set_devuid(sd_device *device, const char *uid) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_add_property_internal(device, "DEVUID", uid);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_devnode_gid(sd_device *device, gid_t *gid) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int device_set_devgid(sd_device *device, const char *gid) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_add_property_internal(device, "DEVGID", gid);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int device_ammend(sd_device *device, const char *key, const char *value) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_set_syspath(device, path, false);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering } else if (streq(key, "USEC_INITIALIZED")) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_set_usec_initialized(device, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_add_devlink(device, devlinks);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlinks);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tags);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_add_property_internal(device, key, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic const char* const device_action_table[_DEVICE_ACTION_MAX] = {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering DeviceAction action = _DEVICE_ACTION_INVALID;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_debug("sd-device: not a key-value pair: '%s'", key);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering action = device_action_from_string(value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering else if (seqnum == 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* kernel only sends seqnum > 0 */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("sd-device: device created from strv lacks devpath, subsystem, action or seqnum");
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mackint device_new_from_strv(sd_device **ret, char **strv) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering DeviceAction action = _DEVICE_ACTION_INVALID;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_append(device, *key, &major, &minor, &seqnum, &action);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_set_devnum(device, major, minor);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_verify(device, action, seqnum);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering DeviceAction action = _DEVICE_ACTION_INVALID;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering unsigned i = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("sd-device: failed to parse nulstr");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_append(device, key, &major, &minor, &seqnum, &action);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_set_devnum(device, major, minor);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_verify(device, action, seqnum);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mackstatic int device_update_properties_bufs(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering size_t allocated_nulstr = 0, allocated_strv = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering FOREACH_DEVICE_PROPERTY(device, prop, val) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering buf_strv = GREEDY_REALLOC0(buf_strv, allocated_strv, strv_size + 2);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering buf_strv[++ strv_size] = (char *)&buf_nulstr[nulstr_len];
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering device->properties_nulstr_len = nulstr_len;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_update_properties_bufs(device);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringint device_get_properties_strv(sd_device *device, char ***strv) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_update_properties_bufs(device);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_devlink_priority(sd_device *device, int *priority) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_get_watch_handle(sd_device *device, int *handle) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringvoid device_set_watch_handle(sd_device *device, int handle) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringint device_rename(sd_device *device, const char *name) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering dirname = dirname_malloc(device->syspath);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering new_syspath = strjoina(dirname, "/", name);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering /* the user must trust that the new name is correct */
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = device_set_syspath(device, new_syspath, false);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = sd_device_get_property_value(device, "INTERFACE", &interface);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = device_add_property_internal(device, "INTERFACE", name);
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = device_add_property_internal(device, "INTERFACE_OLD", interface);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering } else if (r != -ENOENT)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringint device_shallow_clone(sd_device *old_device, sd_device **new_device) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering _cleanup_device_unref_ sd_device *ret = NULL;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = device_set_syspath(ret, old_device->syspath, false);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = device_set_subsystem(ret, old_device->subsystem);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringint device_clone_with_db(sd_device *old_device, sd_device **new_device) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering _cleanup_device_unref_ sd_device *ret = NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = device_shallow_clone(old_device, &ret);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_device_unref_ sd_device *ret = NULL;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = sd_device_new_from_syspath(&ret, syspath);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_add_property_internal(ret, "ACTION", action);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringint device_copy_properties(sd_device *device_dst, sd_device *device_src) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering FOREACH_DEVICE_PROPERTY(device_src, property, value) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = device_add_property(device_dst, property, value);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid device_cleanup_tags(sd_device *device) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid device_cleanup_devlinks(sd_device *device) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering device->property_devlinks_outdated = true;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid device_remove_tag(sd_device *device, const char *tag) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int device_tag(sd_device *device, const char *tag, bool add) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering path = strjoina("/run/udev/tags/", tag, "/", id);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint device_tag_index(sd_device *device, sd_device *device_old, bool add) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* delete possible left-over tags */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r >= 0 && k < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r >= 0 && k < 0)
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poetteringstatic bool device_has_info(sd_device *device) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (!ordered_hashmap_isempty(device->properties_db))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid device_set_db_persist(sd_device *device) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* do not store anything for otherwise empty devices */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* write a database file */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = fopen_temporary(path, &f, &path_tmp);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * set 'sticky' bit to indicate that we should not clean the
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * database when we transition from initramfs to the real root
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "S:%s\n", devlink + strlen("/dev/"));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "L:%i\n", device->devlink_priority);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "W:%i\n", device->watch_handle);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "E:%s=%s\n", property, value);
r = -errno;
goto fail;
fail:
const char *id;
char *path;
return -errno;