device.c revision b92bea5d2a9481de69bb627a7b442a9f58fca43d
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2010 Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <errno.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <sys/epoll.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <libudev.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "unit.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "device.h"
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "strv.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "log.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "unit-name.h"
afc5dbf37fd2399d37976388d9dd9ab470ecf446Lennart Poettering#include "dbus-device.h"
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include "def.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "path-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poetteringstatic const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen [DEVICE_DEAD] = UNIT_INACTIVE,
0b452006de98294d1690f045f6ea2f7f6630ec3bRonny Chevalier [DEVICE_PLUGGED] = UNIT_ACTIVE
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering};
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
15a5e95075a7f6007dd97b2a165c8ed16fe683dfLennart Poetteringstatic void device_unset_sysfs(Device *d) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Device *first;
7ccbd1ae843d77275f2c542582a9a80e5e058a70Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (!d->sysfs)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek /* Remove this unit from the chain of devices which share the
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering * same sysfs path. */
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LIST_REMOVE(Device, same_sysfs, first, d);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek if (first)
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek else
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
f8294e4175918117ca6c131720bcf287eadcd029Josh Triplett free(d->sysfs);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek d->sysfs = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void device_init(Unit *u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Device *d = DEVICE(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(UNIT(d)->load_state == UNIT_STUB);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* In contrast to all other unit types we timeout jobs waiting
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * for devices by default. This is because they otherwise wait
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * indefinitely for plugged in devices, something which cannot
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * happen for the other units since their operations time out
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * anyway. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering UNIT(d)->ignore_on_isolate = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering UNIT(d)->ignore_on_snapshot = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void device_done(Unit *u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Device *d = DEVICE(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_unset_sysfs(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void device_set_state(Device *d, DeviceState state) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DeviceState old_state;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering old_state = d->state;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering d->state = state;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (state != old_state)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering log_debug_unit(UNIT(d)->id,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "%s changed %s -> %s", UNIT(d)->id,
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler device_state_to_string(old_state),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_state_to_string(state));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler}
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int device_coldplug(Unit *u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Device *d = DEVICE(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(d->state == DEVICE_DEAD);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (d->sysfs)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_set_state(d, DEVICE_PLUGGED);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void device_dump(Unit *u, FILE *f, const char *prefix) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Device *d = DEVICE(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fprintf(f,
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering "%sDevice State: %s\n"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "%sSysfs Path: %s\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefix, device_state_to_string(d->state),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefix, strna(d->sysfs));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic UnitActiveState device_active_state(Unit *u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return state_translation_table[DEVICE(u)->state];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic const char *device_sub_state_to_string(Unit *u) {
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering assert(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
3b97fcbd28f92a1e51887fef5de8844a89bde523Lennart Poettering return device_state_to_string(DEVICE(u)->state);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int device_add_escaped_name(Unit *u, const char *dn) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *e;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(dn);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(dn[0] == '/');
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering e = unit_name_from_path(dn, ".device");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!e)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = unit_add_name(u, e);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek free(e);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0 && r != -EEXIST)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *e;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Unit *u;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(dn);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(dn[0] == '/');
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(_u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering e = unit_name_from_path(dn, ".device");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!e)
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering u = manager_get_unit(m, e);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(e);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *_u = u;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *sysfs, *model;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Unit *u = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool delete;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!(sysfs = udev_device_get_syspath(dev)))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((r = device_find_escape_name(m, path, &u)) < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -EEXIST;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!u) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering delete = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering u = unit_new(m, sizeof(Device));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!u)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = device_add_escaped_name(u, path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto fail;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unit_add_to_load_queue(u);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek delete = false;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* If this was created via some dependency and has not
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * actually been seen yet ->sysfs will not be
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * initialized. Hence initialize it if necessary. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!DEVICE(u)->sysfs) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Device *first;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto fail;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!m->devices_by_sysfs)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto fail;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering first = hashmap_get(m->devices_by_sysfs, sysfs);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto fail;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((r = unit_set_description(u, model)) < 0)
ec5ff4445cca6a1d786b8da36cf6fe0acc0b94c8Filipe Brandenburger goto fail;
ec5ff4445cca6a1d786b8da36cf6fe0acc0b94c8Filipe Brandenburger } else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((r = unit_set_description(u, path)) < 0)
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek goto fail;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (main) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* The additional systemd udev properties we only
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering * interpret for the main object */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *wants, *alias;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (alias) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *state, *w;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering size_t l;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering FOREACH_WORD_QUOTED(w, l, alias, state) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *e;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering e = strndup(w, l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!e) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering goto fail;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!is_path(e)) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(e);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering device_update_unit(m, dev, e, false);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(e);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (wants) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *state, *w;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering size_t l;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering FOREACH_WORD_QUOTED(w, l, wants, state) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *e;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering e = strndup(w, l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!e) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering goto fail;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(e);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering goto fail;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering unit_add_to_dbus_queue(u);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringfail:
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_warning("Failed to load device unit: %s", strerror(-r));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (delete && u)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering unit_free(u);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering const char *sysfs, *dn;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct udev_list_entry *item = NULL, *first = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(m);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!(sysfs = udev_device_get_syspath(dev)))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Add the main unit named after the sysfs path */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_update_unit(m, dev, sysfs, true);
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering /* Add an additional unit for the device node */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((dn = udev_device_get_devnode(dev)))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_update_unit(m, dev, dn, false);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering /* Add additional units for all symlinks */
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering first = udev_device_get_devlinks_list_entry(dev);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering udev_list_entry_foreach(item, first) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct stat st;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering /* Don't bother with the /dev/block links */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering p = udev_list_entry_get_name(item);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (path_startswith(p, "/dev/block/") ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering path_startswith(p, "/dev/char/"))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek /* Verify that the symlink in the FS actually belongs
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * to this device. This is useful to deal with
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * conflicting devices, e.g. when two disks want the
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * same /dev/disk/by-label/xxx link because they have
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * the same label. We want to make sure that the same
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * device that won the symlink wins in systemd, so we
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering * check the device node major/minor*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (stat(p, &st) >= 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering st.st_rdev != udev_device_get_devnum(dev))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_update_unit(m, dev, p, false);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen if (update_state) {
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Device *d, *l;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering manager_dispatch_load_queue(m);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering l = hashmap_get(m->devices_by_sysfs, sysfs);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LIST_FOREACH(same_sysfs, d, l)
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering device_set_state(d, DEVICE_PLUGGED);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering }
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poetteringstatic int device_process_path(Manager *m, const char *path, bool update_state) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct udev_device *dev;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(path);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_warning("Failed to get udev device object from udev for path %s.", path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = device_process_new_device(m, dev, update_state);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering udev_device_unref(dev);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int device_process_removed_device(Manager *m, struct udev_device *dev) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *sysfs;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering Device *d;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(dev);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!(sysfs = udev_device_get_syspath(dev)))
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering return -ENOMEM;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
03ee5c38cb0da193dd08733fb4c0c2809cee6a99Lennart Poettering /* Remove all units of this sysfs path */
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_unset_sysfs(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering device_set_state(d, DEVICE_DEAD);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic Unit *device_following(Unit *u) {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt Device *d = DEVICE(u);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt Device *other, *first = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4a61c3e51e96a747c30598d78ee3a24e7c569e9fZbigniew Jędrzejewski-Szmek assert(d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (startswith(u->id, "sys-"))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt /* Make everybody follow the unit that's named after the sysfs path */
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (startswith(UNIT(other)->id, "sys-"))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return UNIT(other);
6355e75610a8d47fc3ba5ab8bd442172a2cfe574Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering if (startswith(UNIT(other)->id, "sys-"))
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt return UNIT(other);
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering first = other;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return UNIT(first);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8531ae707d4d0203e83304d4af948b8169a5fce1Lennart Poetteringstatic int device_following_set(Unit *u, Set **_s) {
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt Device *d = DEVICE(u);
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt Device *other;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Set *s;
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo int r;
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo assert(d);
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo assert(_s);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!d->same_sysfs_prev && !d->same_sysfs_next) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering *_s = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return 0;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (!(s = set_new(NULL, NULL)))
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return -ENOMEM;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if ((r = set_put(s, other)) < 0)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering goto fail;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if ((r = set_put(s, other)) < 0)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering goto fail;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering *_s = s;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return 1;
fail:
set_free(s);
return r;
}
static void device_shutdown(Manager *m) {
assert(m);
if (m->udev_monitor) {
udev_monitor_unref(m->udev_monitor);
m->udev_monitor = NULL;
}
if (m->udev) {
udev_unref(m->udev);
m->udev = NULL;
}
hashmap_free(m->devices_by_sysfs);
m->devices_by_sysfs = NULL;
}
static int device_enumerate(Manager *m) {
int r;
struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
assert(m);
if (!m->udev) {
struct epoll_event ev;
if (!(m->udev = udev_new()))
return -ENOMEM;
if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
r = -ENOMEM;
goto fail;
}
/* This will fail if we are unprivileged, but that
* should not matter much, as user instances won't run
* during boot. */
udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
r = -ENOMEM;
goto fail;
}
if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
r = -EIO;
goto fail;
}
m->udev_watch.type = WATCH_UDEV;
m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
zero(ev);
ev.events = EPOLLIN;
ev.data.ptr = &m->udev_watch;
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
return -errno;
}
if (!(e = udev_enumerate_new(m->udev))) {
r = -ENOMEM;
goto fail;
}
if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
r = -EIO;
goto fail;
}
if (udev_enumerate_scan_devices(e) < 0) {
r = -EIO;
goto fail;
}
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first)
device_process_path(m, udev_list_entry_get_name(item), false);
udev_enumerate_unref(e);
return 0;
fail:
if (e)
udev_enumerate_unref(e);
device_shutdown(m);
return r;
}
void device_fd_event(Manager *m, int events) {
struct udev_device *dev;
int r;
const char *action, *ready;
assert(m);
if (events != EPOLLIN) {
static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
if (!ratelimit_test(&limit))
log_error("Failed to get udev event: %m");
if (!(events & EPOLLIN))
return;
}
if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
/*
* libudev might filter-out devices which pass the bloom filter,
* so getting NULL here is not necessarily an error
*/
return;
}
if (!(action = udev_device_get_action(dev))) {
log_error("Failed to get udev action string.");
goto fail;
}
ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
if ((r = device_process_removed_device(m, dev)) < 0) {
log_error("Failed to process udev device event: %s", strerror(-r));
goto fail;
}
} else {
if ((r = device_process_new_device(m, dev, true)) < 0) {
log_error("Failed to process udev device event: %s", strerror(-r));
goto fail;
}
}
fail:
udev_device_unref(dev);
}
static const char* const device_state_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = "dead",
[DEVICE_PLUGGED] = "plugged"
};
DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
const UnitVTable device_vtable = {
.object_size = sizeof(Device),
.sections =
"Unit\0"
"Device\0"
"Install\0",
.no_instances = true,
.init = device_init,
.load = unit_load_fragment_and_dropin_optional,
.done = device_done,
.coldplug = device_coldplug,
.dump = device_dump,
.active_state = device_active_state,
.sub_state_to_string = device_sub_state_to_string,
.bus_interface = "org.freedesktop.systemd1.Device",
.bus_message_handler = bus_device_message_handler,
.bus_invalidating_properties = bus_device_invalidating_properties,
.following = device_following,
.following_set = device_following_set,
.enumerate = device_enumerate,
.shutdown = device_shutdown,
.status_message_formats = {
.starting_stopping = {
[0] = "Expecting device %s...",
},
.finished_start_job = {
[JOB_DONE] = "Found device %s.",
[JOB_TIMEOUT] = "Timed out waiting for device %s.",
},
},
};