57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/***
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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
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
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 Gundersen***/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include <ctype.h>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include <net/if.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/types.h>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "sd-device.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "device-internal.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "device-private.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "device-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "fileio.h"
f4f15635ec05293ffcc83a5b39f624bbabbd8fd0Lennart Poettering#include "fs-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "hashmap.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "macro.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "mkdir.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "parse-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "path-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "refcnt.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "set.h"
8b43440b7ef4b81c69c31de7ff820dc07a780254Lennart Poettering#include "string-table.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "strv.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "strxcpyx.h"
ee104e11e303499a637c5cd8157bd12ad5cc116dLennart Poettering#include "user-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_property(sd_device *device, const char *key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_aux(device, key, value, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (key[0] != '.') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_aux(device, key, value, true);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_add_property_internal_from_string(sd_device *device, const char *str) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(str);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = strdup(str);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = strchr(key, '=');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *value = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (isempty(++value))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int handle_db_line(sd_device *device, char key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'S':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/dev/", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_devlink(device, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'L':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atoi(value, &device->devlink_priority);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'E':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal_from_string(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'G':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_tag(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'W':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atoi(value, &device->watch_handle);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'I':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_usec_initialized(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("device db: unknown key '%c'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_set_devlink_priority(sd_device *device, int priority) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlink_priority = priority;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_set_is_initialized(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->is_initialized = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char num[DECIMAL_STR_MAX(usec_t)];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen usec_t usec_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device_old && device_old->usec_initialized > 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen usec_initialized = device_old->usec_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen usec_initialized = now(CLOCK_MONOTONIC);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_usec_initialized(device, num);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_read_db(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *db = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *id, *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t db_len;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen enum {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen INVALID_LINE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->db_loaded || device->sealed)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_id_filename(device, &id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/run/udev/data/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = read_full_file(path, &db, &db_len);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r == -ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering else
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* devices with a database entry are initialized */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device_set_is_initialized(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < db_len; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (state) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!strchr(NEWLINE, db[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = db[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (db[i] != ':') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = INVALID_LINE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen db[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = &db[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case INVALID_LINE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (strchr(NEWLINE, db[i]))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (strchr(NEWLINE, db[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen db[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = handle_db_line(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("invalid state when parsing db");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->db_loaded = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenuint64_t device_get_properties_generation(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device->properties_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenuint64_t device_get_tags_generation(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device->tags_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenuint64_t device_get_devlinks_generation(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device->devlinks_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_devnode_mode(sd_device *device, mode_t *mode) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(mode);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *mode = device->devmode;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_devnode_uid(sd_device *device, uid_t *uid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(uid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *uid = device->devuid;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_set_devuid(sd_device *device, const char *uid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned u;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(uid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou(uid, &u);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVUID", uid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devuid = u;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_devnode_gid(sd_device *device, gid_t *gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(gid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *gid = device->devgid;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_set_devgid(sd_device *device, const char *gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned g;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(gid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou(gid, &g);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVGID", gid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devgid = g;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
401cb61499f446c7c1579a160eeef435afd525fdTom Gundersenstatic int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq(key, "DEVPATH")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/sys", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_syspath(device, path, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "SUBSYSTEM")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVTYPE")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devtype(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVNAME")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devname(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "USEC_INITIALIZED")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_usec_initialized(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DRIVER")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_driver(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "IFINDEX")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_ifindex(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVMODE")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devmode(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVUID")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devuid(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVGID")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devgid(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVLINKS")) {
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen const char *word, *state;
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen size_t l;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen FOREACH_WORD(word, l, value, state) {
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen char devlink[l + 1];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen strncpy(devlink, word, l);
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen devlink[l] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen r = device_add_devlink(device, devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "TAGS")) {
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen const char *word, *state;
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen size_t l;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen FOREACH_WORD_SEPARATOR(word, l, value, ":", state) {
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen char tag[l + 1];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen (void)strncpy(tag, word, l);
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen tag[l] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen r = device_add_tag(device, tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic const char* const device_action_table[_DEVICE_ACTION_MAX] = {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_ADD] = "add",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_REMOVE] = "remove",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_CHANGE] = "change",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_MOVE] = "move",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_ONLINE] = "online",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen [DEVICE_ACTION_OFFLINE] = "offline",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen};
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom GundersenDEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DeviceAction *_action) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DeviceAction action = _DEVICE_ACTION_INVALID;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint64_t seqnum = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *major = NULL, *minor = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_major);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_seqnum);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_action);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = strchr(key, '=');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: not a key-value pair: '%s'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *value = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq(key, "MAJOR"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen major = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (streq(key, "MINOR"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen minor = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq(key, "ACTION")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen action = device_action_from_string(value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (action == _DEVICE_ACTION_INVALID)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "SEQNUM")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou64(value, &seqnum);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (seqnum == 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* kernel only sends seqnum > 0 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
401cb61499f446c7c1579a160eeef435afd525fdTom Gundersen r = device_amend(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_major = major;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (minor != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_minor = minor;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (action != _DEVICE_ACTION_INVALID)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_action = action;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (seqnum > 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_seqnum = seqnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_seal(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sealed = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sealed = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_new_from_strv(sd_device **ret, char **strv) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char **key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *major = NULL, *minor = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DeviceAction action = _DEVICE_ACTION_INVALID;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint64_t seqnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(strv);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_new_aux(&device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen STRV_FOREACH(key, strv) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_append(device, *key, &major, &minor, &seqnum, &action);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devnum(device, major, minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_verify(device, action, seqnum);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 const char *major = NULL, *minor = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DeviceAction action = _DEVICE_ACTION_INVALID;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint64_t seqnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned i = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(nulstr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(len);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_new_aux(&device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (i < len) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *end;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = (char*)&nulstr[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen end = memchr(key, '\0', len - i);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!end) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: failed to parse nulstr");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen i += end - key + 1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_append(device, key, &major, &minor, &seqnum, &action);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devnum(device, major, minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_verify(device, action, seqnum);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_update_properties_bufs(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *val, *prop;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen _cleanup_free_ char **buf_strv = NULL;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen _cleanup_free_ uint8_t *buf_nulstr = NULL;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt size_t allocated_nulstr = 0;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen size_t nulstr_len = 0, num = 0, i = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen if (!device->properties_buf_outdated)
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen return 0;
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_PROPERTY(device, prop, val) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t len = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen len = strlen(prop) + 1 + strlen(val);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!buf_nulstr)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen nulstr_len += len + 1;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt ++num;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen /* build buf_strv from buf_nulstr */
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen buf_strv = new0(char *, num + 1);
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen if (!buf_strv)
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen return -ENOMEM;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt NULSTR_FOREACH(val, (char*) buf_nulstr) {
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen buf_strv[i] = (char *) val;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt assert(i < num);
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt i++;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen free(device->properties_nulstr);
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen device->properties_nulstr = buf_nulstr;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen buf_nulstr = NULL;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen device->properties_nulstr_len = nulstr_len;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen free(device->properties_strv);
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen device->properties_strv = buf_strv;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen buf_strv = NULL;
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_buf_outdated = false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(nulstr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(len);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen r = device_update_properties_bufs(device);
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen if (r < 0)
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *nulstr = device->properties_nulstr;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *len = device->properties_nulstr_len;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_properties_strv(sd_device *device, char ***strv) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(strv);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_update_properties_bufs(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *strv = device->properties_strv;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_devlink_priority(sd_device *device, int *priority) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(priority);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *priority = device->devlink_priority;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_watch_handle(sd_device *device, int *handle) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(handle);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *handle = device->watch_handle;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_set_watch_handle(sd_device *device, int handle) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->watch_handle = handle;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_rename(sd_device *device, const char *name) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *dirname = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *new_syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *interface;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dirname = dirname_malloc(device->syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!dirname)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen new_syspath = strjoina(dirname, "/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* the user must trust that the new name is correct */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_syspath(device, new_syspath, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (r != -ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(old_device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(new_device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_new_aux(&ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_syspath(ret, old_device->syspath, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(ret, old_device->subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret->devnum = old_device->devnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *new_device = ret;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(old_device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(new_device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_shallow_clone(old_device, &ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret->sealed = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *new_device = ret;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(new_device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(action);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_new_from_syspath(&ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(ret, "ACTION", action);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *new_device = ret;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_copy_properties(sd_device *device_dst, sd_device *device_src) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *property, *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device_dst);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device_src);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_PROPERTY(device_src, property, value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property(device_dst, property, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_cleanup_tags(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen set_free_free(device->tags);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_tags_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_cleanup_devlinks(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen set_free_free(device->devlinks);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_devlinks_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_remove_tag(sd_device *device, const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(set_remove(device->tags, tag));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_tags_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_tag(sd_device *device, const char *tag, bool add) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *id;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_id_filename(device, &id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/run/udev/tags/", tag, "/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (add) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = unlink(path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0 && errno != ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_tag_index(sd_device *device, sd_device *device_old, bool add) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *tag;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r = 0, k;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (add && device_old) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* delete possible left-over tags */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_TAG(device_old, tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!sd_device_has_tag(device, tag)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen k = device_tag(device_old, tag, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0 && k < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = k;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_TAG(device, tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen k = device_tag(device, tag, add);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0 && k < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = k;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic bool device_has_info(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!set_isempty(device->devlinks))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->devlink_priority != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!ordered_hashmap_isempty(device->properties_db))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!set_isempty(device->tags))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->watch_handle >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid device_set_db_persist(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->db_persist = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_update_db(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *id;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_fclose_ FILE *f = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *path_tmp = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen bool has_info;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen has_info = device_has_info(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_id_filename(device, &id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/run/udev/data/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* do not store anything for otherwise empty devices */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = unlink(path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0 && errno != ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* write a database file */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = mkdir_parents(path, 0755);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = fopen_temporary(path, &f, &path_tmp);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /*
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 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->db_persist) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = fchmod(fileno(f), 01644);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen goto fail;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = fchmod(fileno(f), 0644);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen goto fail;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (has_info) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *property, *value, *tag;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Iterator i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major(device->devnum) > 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *devlink;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_DEVLINK(device, devlink)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "S:%s\n", devlink + strlen("/dev/"));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->devlink_priority != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "L:%i\n", device->devlink_priority);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->watch_handle >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "W:%i\n", device->watch_handle);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->usec_initialized > 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "E:%s=%s\n", property, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen FOREACH_DEVICE_TAG(device, tag)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(f, "G:%s\n", tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = fflush_and_check(f);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen goto fail;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = rename(path_tmp, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen goto fail;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path, device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenfail:
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering (void) unlink(path);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering (void) unlink(path_tmp);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering return log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_delete_db(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *id;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_id_filename(device, &id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/run/udev/data/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = unlink(path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0 && errno != ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersenint device_read_db_force(sd_device *device) {
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen assert(device);
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen return device_read_db_aux(device, true);
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen}