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