device-private.c revision 401cb61499f446c7c1579a160eeef435afd525fd
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <ctype.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/types.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <net/if.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "util.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "macro.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "refcnt.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "path-util.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "strxcpyx.h"
c34255bdb217c2a1d3ac6348252437ab8be9ca46Lennart Poettering#include "fileio.h"
24882e06c135584f16f31ba8a00fecde8b7f6fadLennart Poettering#include "hashmap.h"
24882e06c135584f16f31ba8a00fecde8b7f6fadLennart Poettering#include "set.h"
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering#include "strv.h"
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering#include "mkdir.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "sd-device.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "device-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "device-internal.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "device-private.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint device_add_property(sd_device *device, const char *key, const char *value) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt assert(device);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt assert(key);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d3e84ddb885e9d5f0ae9930eb905910e3a81f157Lennart Poettering r = device_add_property_aux(device, key, value, false);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (key[0] != '.') {
afc6adb5ec7e73bc13156c43f52fb015cd80cc68Lennart Poettering r = device_add_property_aux(device, key, value, true);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
cde93897cdefdd7c7f66c400a61e42ceee5f6a46Lennart Poettering}
cde93897cdefdd7c7f66c400a61e42ceee5f6a46Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int device_add_property_internal_from_string(sd_device *device, const char *str) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_free_ char *key = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char *value;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering assert(str);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering key = strdup(str);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!key)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering value = strchr(key, '=');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!value)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EINVAL;
d3e84ddb885e9d5f0ae9930eb905910e3a81f157Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *value = '\0';
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering if (isempty(++value))
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering value = NULL;
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering return device_add_property_internal(device, key, value);
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering}
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poetteringstatic int handle_db_line(sd_device *device, char key, const char *value) {
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering char *path;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(device);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(value);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering switch (key) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case 'S':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering path = strjoina("/dev/", value);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_add_devlink(device, path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case 'L':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = safe_atoi(value, &device->devlink_priority);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt case 'E':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_add_property_internal_from_string(device, value);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case 'G':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_add_tag(device, value);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering break;
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering case 'W':
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering r = safe_atoi(value, &device->watch_handle);
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case 'I':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_set_usec_initialized(device, value);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering default:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("device db: unknown key '%c'", key);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid device_set_devlink_priority(sd_device *device, int priority) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering device->devlink_priority = priority;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid device_set_is_initialized(sd_device *device) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
76b543756ef69ce69784d571aefe8de65eaeb331Lennart Poettering device->is_initialized = true;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt}
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering char num[DECIMAL_STR_MAX(usec_t)];
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt usec_t usec_initialized;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering assert(device);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (device_old && device_old->usec_initialized > 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering usec_initialized = device_old->usec_initialized;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering else
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt usec_initialized = now(CLOCK_MONOTONIC);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering if (r < 0)
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering return -errno;
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering r = device_set_usec_initialized(device, num);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering if (r < 0)
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering return r;
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int device_read_db(sd_device *device) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_free_ char *db = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char *path;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const char *id, *value;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char key;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering size_t db_len;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned i;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt int r;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering enum {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering PRE_KEY,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering KEY,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering PRE_VALUE,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering VALUE,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering INVALID_LINE,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } state = PRE_KEY;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(device);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (device->db_loaded || device->sealed)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return 0;
943aca8efb39453e3994ccdd1e08534b788c5aeeLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = device_get_id_filename(device, &id);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering path = strjoina("/run/udev/data/", id);
11b90e69e5620c2483b019340eff121d504db115Lennart Poettering
11b90e69e5620c2483b019340eff121d504db115Lennart Poettering r = read_full_file(path, &db, &db_len);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r == -ENOENT)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return 0;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* devices with a database entry are initialized */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering device_set_is_initialized(device);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (i = 0; i < db_len; i++) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering switch (state) {
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt case PRE_KEY:
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (!strchr(NEWLINE, db[i])) {
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering key = db[i];
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering state = KEY;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case KEY:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (db[i] != ':') {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering state = INVALID_LINE;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering db[i] = '\0';
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
5bb658a1784a0fd4f0f32adb4b1fb636ff503f7dKay Sievers state = PRE_VALUE;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt }
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case PRE_VALUE:
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt value = &db[i];
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering state = VALUE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case INVALID_LINE:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (strchr(NEWLINE, db[i]))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering state = PRE_KEY;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case VALUE:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (strchr(NEWLINE, db[i])) {
71fda00f320379f5cbee8e118848de98caaa229dLennart Poettering db[i] = '\0';
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = handle_db_line(device, key, value);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering state = PRE_KEY;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering break;
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering default:
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering assert_not_reached("invalid state when parsing db");
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering }
49f3fffd94591bdf2bd6c2233a9300daeab79566Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering device->db_loaded = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringuint64_t device_get_properties_generation(sd_device *device) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return device->properties_generation;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringuint64_t device_get_tags_generation(sd_device *device) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return device->tags_generation;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringuint64_t device_get_devlinks_generation(sd_device *device) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return device->devlinks_generation;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint device_get_devnode_mode(sd_device *device, mode_t *mode) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(mode);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering r = device_read_db(device);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *mode = device->devmode;
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poetteringint device_get_devnode_uid(sd_device *device, uid_t *uid) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering assert(device);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering assert(uid);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering r = device_read_db(device);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *uid = device->devuid;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int device_set_devuid(sd_device *device, const char *uid) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned u;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(uid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = safe_atou(uid, &u);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_add_property_internal(device, "DEVUID", uid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering device->devuid = u;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poetteringint device_get_devnode_gid(sd_device *device, gid_t *gid) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_read_db(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *gid = device->devgid;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int device_set_devgid(sd_device *device, const char *gid) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned g;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(device);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(gid);
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = safe_atou(gid, &g);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
3e044c492e3ebe64f4e3175c94f9db8a62557b82Markus Elfring return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = device_add_property_internal(device, "DEVGID", gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
return r;
device->devgid = g;
return 0;
}
static int device_amend(sd_device *device, const char *key, const char *value) {
int r;
assert(device);
assert(key);
assert(value);
if (streq(key, "DEVPATH")) {
char *path;
path = strjoina("/sys", value);
/* the caller must verify or trust this data (e.g., if it comes from the kernel) */
r = device_set_syspath(device, path, false);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path);
} else if (streq(key, "SUBSYSTEM")) {
r = device_set_subsystem(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value);
} else if (streq(key, "DEVTYPE")) {
r = device_set_devtype(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value);
} else if (streq(key, "DEVNAME")) {
r = device_set_devname(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value);
} else if (streq(key, "USEC_INITIALIZED")) {
r = device_set_usec_initialized(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value);
} else if (streq(key, "DRIVER")) {
r = device_set_driver(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value);
} else if (streq(key, "IFINDEX")) {
r = device_set_ifindex(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value);
} else if (streq(key, "DEVMODE")) {
r = device_set_devmode(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value);
} else if (streq(key, "DEVUID")) {
r = device_set_devuid(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value);
} else if (streq(key, "DEVGID")) {
r = device_set_devgid(device, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value);
} else if (streq(key, "DEVLINKS")) {
const char *word, *state;
size_t l;
FOREACH_WORD(word, l, value, state) {
char *devlink;
devlink = strndupa(word, l);
r = device_add_devlink(device, devlink);
if (r < 0)
return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlink);
}
} else if (streq(key, "TAGS")) {
const char *word, *state;
size_t l;
FOREACH_WORD_SEPARATOR(word, l, value, ":", state) {
char *tag;
tag = strndupa(word, l);
r = device_add_tag(device, tag);
if (r < 0)
return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tag);
}
} else {
r = device_add_property_internal(device, key, value);
if (r < 0)
return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value);
}
return 0;
}
static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
[DEVICE_ACTION_ADD] = "add",
[DEVICE_ACTION_REMOVE] = "remove",
[DEVICE_ACTION_CHANGE] = "change",
[DEVICE_ACTION_MOVE] = "move",
[DEVICE_ACTION_ONLINE] = "online",
[DEVICE_ACTION_OFFLINE] = "offline",
};
DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
static int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
DeviceAction *_action) {
DeviceAction action = _DEVICE_ACTION_INVALID;
uint64_t seqnum = 0;
const char *major = NULL, *minor = NULL;
char *value;
int r;
assert(device);
assert(key);
assert(_major);
assert(_minor);
assert(_seqnum);
assert(_action);
value = strchr(key, '=');
if (!value) {
log_debug("sd-device: not a key-value pair: '%s'", key);
return -EINVAL;
}
*value = '\0';
value++;
if (streq(key, "MAJOR"))
major = value;
else if (streq(key, "MINOR"))
minor = value;
else {
if (streq(key, "ACTION")) {
action = device_action_from_string(value);
if (action == _DEVICE_ACTION_INVALID)
return -EINVAL;
} else if (streq(key, "SEQNUM")) {
r = safe_atou64(value, &seqnum);
if (r < 0)
return r;
else if (seqnum == 0)
/* kernel only sends seqnum > 0 */
return -EINVAL;
}
r = device_amend(device, key, value);
if (r < 0)
return r;
}
if (major != 0)
*_major = major;
if (minor != 0)
*_minor = minor;
if (action != _DEVICE_ACTION_INVALID)
*_action = action;
if (seqnum > 0)
*_seqnum = seqnum;
return 0;
}
void device_seal(sd_device *device) {
assert(device);
device->sealed = true;
}
static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
assert(device);
if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
log_debug("sd-device: device created from strv lacks devpath, subsystem, action or seqnum");
return -EINVAL;
}
device->sealed = true;
return 0;
}
int device_new_from_strv(sd_device **ret, char **strv) {
_cleanup_device_unref_ sd_device *device = NULL;
char **key;
const char *major = NULL, *minor = NULL;
DeviceAction action = _DEVICE_ACTION_INVALID;
uint64_t seqnum;
int r;
assert(ret);
assert(strv);
r = device_new_aux(&device);
if (r < 0)
return r;
STRV_FOREACH(key, strv) {
r = device_append(device, *key, &major, &minor, &seqnum, &action);
if (r < 0)
return r;
}
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
}
r = device_verify(device, action, seqnum);
if (r < 0)
return r;
*ret = device;
device = NULL;
return 0;
}
int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
_cleanup_device_unref_ sd_device *device = NULL;
const char *major = NULL, *minor = NULL;
DeviceAction action = _DEVICE_ACTION_INVALID;
uint64_t seqnum;
unsigned i = 0;
int r;
assert(ret);
assert(nulstr);
assert(len);
r = device_new_aux(&device);
if (r < 0)
return r;
while (i < len) {
char *key;
const char *end;
key = (char*)&nulstr[i];
end = memchr(key, '\0', len - i);
if (!end) {
log_debug("sd-device: failed to parse nulstr");
return -EINVAL;
}
i += end - key + 1;
r = device_append(device, key, &major, &minor, &seqnum, &action);
if (r < 0)
return r;
}
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
}
r = device_verify(device, action, seqnum);
if (r < 0)
return r;
*ret = device;
device = NULL;
return 0;
}
static int device_update_properties_bufs(sd_device *device) {
const char *val, *prop;
char **buf_strv = NULL;
uint8_t *buf_nulstr = NULL;
size_t allocated_nulstr = 0, allocated_strv = 0;
size_t nulstr_len = 0, strv_size = 0;
assert(device);
if (!device->properties_buf_outdated)
return 0;
FOREACH_DEVICE_PROPERTY(device, prop, val) {
size_t len = 0;
len = strlen(prop) + 1 + strlen(val);
buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
if (!buf_nulstr)
return -ENOMEM;
buf_strv = GREEDY_REALLOC0(buf_strv, allocated_strv, strv_size + 2);
if (!buf_strv)
return -ENOMEM;
buf_strv[++ strv_size] = (char *)&buf_nulstr[nulstr_len];
strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
nulstr_len += len + 1;
}
free(device->properties_nulstr);
free(device->properties_strv);
device->properties_nulstr = buf_nulstr;
device->properties_nulstr_len = nulstr_len;
device->properties_strv = buf_strv;
device->properties_buf_outdated = false;
return 0;
}
int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
int r;
assert(device);
assert(nulstr);
assert(len);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
*nulstr = device->properties_nulstr;
*len = device->properties_nulstr_len;
return 0;
}
int device_get_properties_strv(sd_device *device, char ***strv) {
int r;
assert(device);
assert(strv);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
*strv = device->properties_strv;
return 0;
}
int device_get_devlink_priority(sd_device *device, int *priority) {
int r;
assert(device);
assert(priority);
r = device_read_db(device);
if (r < 0)
return r;
*priority = device->devlink_priority;
return 0;
}
int device_get_watch_handle(sd_device *device, int *handle) {
int r;
assert(device);
assert(handle);
r = device_read_db(device);
if (r < 0)
return r;
*handle = device->watch_handle;
return 0;
}
void device_set_watch_handle(sd_device *device, int handle) {
assert(device);
device->watch_handle = handle;
}
int device_rename(sd_device *device, const char *name) {
_cleanup_free_ char *dirname = NULL;
char *new_syspath;
const char *interface;
int r;
assert(device);
assert(name);
dirname = dirname_malloc(device->syspath);
if (!dirname)
return -ENOMEM;
new_syspath = strjoina(dirname, "/", name);
/* the user must trust that the new name is correct */
r = device_set_syspath(device, new_syspath, false);
if (r < 0)
return r;
r = sd_device_get_property_value(device, "INTERFACE", &interface);
if (r >= 0) {
r = device_add_property_internal(device, "INTERFACE", name);
if (r < 0)
return r;
/* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
r = device_add_property_internal(device, "INTERFACE_OLD", interface);
if (r < 0)
return r;
} else if (r != -ENOENT)
return r;
return 0;
}
int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
_cleanup_device_unref_ sd_device *ret = NULL;
int r;
assert(old_device);
assert(new_device);
r = device_new_aux(&ret);
if (r < 0)
return r;
r = device_set_syspath(ret, old_device->syspath, false);
if (r < 0)
return r;
r = device_set_subsystem(ret, old_device->subsystem);
if (r < 0)
return r;
ret->devnum = old_device->devnum;
*new_device = ret;
ret = NULL;
return 0;
}
int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
_cleanup_device_unref_ sd_device *ret = NULL;
int r;
assert(old_device);
assert(new_device);
r = device_shallow_clone(old_device, &ret);
if (r < 0)
return r;
r = device_read_db(ret);
if (r < 0)
return r;
ret->sealed = true;
*new_device = ret;
ret = NULL;
return 0;
}
int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
_cleanup_device_unref_ sd_device *ret = NULL;
int r;
assert(new_device);
assert(syspath);
assert(action);
r = sd_device_new_from_syspath(&ret, syspath);
if (r < 0)
return r;
r = device_read_uevent_file(ret);
if (r < 0)
return r;
r = device_add_property_internal(ret, "ACTION", action);
if (r < 0)
return r;
*new_device = ret;
ret = NULL;
return 0;
}
int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
const char *property, *value;
int r;
assert(device_dst);
assert(device_src);
FOREACH_DEVICE_PROPERTY(device_src, property, value) {
r = device_add_property(device_dst, property, value);
if (r < 0)
return r;
}
return 0;
}
void device_cleanup_tags(sd_device *device) {
assert(device);
set_free_free(device->tags);
device->tags = NULL;
device->property_tags_outdated = true;
device->tags_generation ++;
}
void device_cleanup_devlinks(sd_device *device) {
assert(device);
set_free_free(device->devlinks);
device->devlinks = NULL;
device->property_devlinks_outdated = true;
device->devlinks_generation ++;
}
void device_remove_tag(sd_device *device, const char *tag) {
assert(device);
assert(tag);
free(set_remove(device->tags, tag));
device->property_tags_outdated = true;
device->tags_generation ++;
}
static int device_tag(sd_device *device, const char *tag, bool add) {
const char *id;
char *path;
int r;
assert(device);
assert(tag);
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/tags/", tag, "/", id);
if (add) {
r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
if (r < 0)
return r;
} else {
r = unlink(path);
if (r < 0 && errno != ENOENT)
return -errno;
}
return 0;
}
int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
const char *tag;
int r = 0, k;
if (add && device_old) {
/* delete possible left-over tags */
FOREACH_DEVICE_TAG(device_old, tag) {
if (!sd_device_has_tag(device, tag)) {
k = device_tag(device_old, tag, false);
if (r >= 0 && k < 0)
r = k;
}
}
}
FOREACH_DEVICE_TAG(device, tag) {
k = device_tag(device, tag, add);
if (r >= 0 && k < 0)
r = k;
}
return r;
}
static bool device_has_info(sd_device *device) {
assert(device);
if (!set_isempty(device->devlinks))
return true;
if (device->devlink_priority != 0)
return true;
if (!ordered_hashmap_isempty(device->properties_db))
return true;
if (!set_isempty(device->tags))
return true;
if (device->watch_handle >= 0)
return true;
return false;
}
void device_set_db_persist(sd_device *device) {
assert(device);
device->db_persist = true;
}
int device_update_db(sd_device *device) {
const char *id;
char *path;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *path_tmp = NULL;
bool has_info;
int r;
assert(device);
has_info = device_has_info(device);
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/data/", id);
/* do not store anything for otherwise empty devices */
if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
r = unlink(path);
if (r < 0 && errno != ENOENT)
return -errno;
return 0;
}
/* write a database file */
r = mkdir_parents(path, 0755);
if (r < 0)
return r;
r = fopen_temporary(path, &f, &path_tmp);
if (r < 0)
return r;
/*
* set 'sticky' bit to indicate that we should not clean the
* database when we transition from initramfs to the real root
*/
if (device->db_persist) {
r = fchmod(fileno(f), 01644);
if (r < 0) {
r = -errno;
goto fail;
}
} else {
r = fchmod(fileno(f), 0644);
if (r < 0) {
r = -errno;
goto fail;
}
}
if (has_info) {
const char *property, *value, *tag;
Iterator i;
if (major(device->devnum) > 0) {
const char *devlink;
FOREACH_DEVICE_DEVLINK(device, devlink)
fprintf(f, "S:%s\n", devlink + strlen("/dev/"));
if (device->devlink_priority != 0)
fprintf(f, "L:%i\n", device->devlink_priority);
if (device->watch_handle >= 0)
fprintf(f, "W:%i\n", device->watch_handle);
}
if (device->usec_initialized > 0)
fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
fprintf(f, "E:%s=%s\n", property, value);
FOREACH_DEVICE_TAG(device, tag)
fprintf(f, "G:%s\n", tag);
}
r = fflush_and_check(f);
if (r < 0)
goto fail;
r = rename(path_tmp, path);
if (r < 0) {
r = -errno;
goto fail;
}
log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
path, device->devpath);
return 0;
fail:
log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty",
path, device->devpath);
unlink(path);
unlink(path_tmp);
return r;
}
int device_delete_db(sd_device *device) {
const char *id;
char *path;
int r;
assert(device);
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/data/", id);
r = unlink(path);
if (r < 0 && errno != ENOENT)
return -errno;
return 0;
}