2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2010-02-03 13:03:47 +01:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2010 Lennart Poettering
|
|
|
|
***/
|
|
|
|
|
2010-01-28 06:46:33 +01:00
|
|
|
#include <errno.h>
|
2010-01-29 06:45:59 +01:00
|
|
|
#include <sys/epoll.h>
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2015-11-17 06:52:45 +01:00
|
|
|
#include "libudev.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2010-04-18 03:08:16 +02:00
|
|
|
#include "dbus-device.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "device.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "log.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2012-05-07 21:36:12 +02:00
|
|
|
#include "path-util.h"
|
2015-10-26 22:01:44 +01:00
|
|
|
#include "stat-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
|
|
|
#include "swap.h"
|
2013-11-19 21:12:59 +01:00
|
|
|
#include "udev-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "unit-name.h"
|
2013-11-25 21:08:39 +01:00
|
|
|
#include "unit.h"
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
|
|
|
|
[DEVICE_DEAD] = UNIT_INACTIVE,
|
2015-02-27 21:55:08 +01:00
|
|
|
[DEVICE_TENTATIVE] = UNIT_ACTIVATING,
|
|
|
|
[DEVICE_PLUGGED] = UNIT_ACTIVE,
|
2010-01-29 03:18:09 +01:00
|
|
|
};
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
|
|
2010-07-20 20:33:19 +02:00
|
|
|
static void device_unset_sysfs(Device *d) {
|
2013-11-25 15:25:01 +01:00
|
|
|
Hashmap *devices;
|
2010-07-20 20:33:19 +02:00
|
|
|
Device *first;
|
|
|
|
|
|
|
|
assert(d);
|
|
|
|
|
2010-07-21 05:00:29 +02:00
|
|
|
if (!d->sysfs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Remove this unit from the chain of devices which share the
|
|
|
|
* same sysfs path. */
|
2013-11-25 15:25:01 +01:00
|
|
|
devices = UNIT(d)->manager->devices_by_sysfs;
|
|
|
|
first = hashmap_get(devices, d->sysfs);
|
2013-10-14 06:10:14 +02:00
|
|
|
LIST_REMOVE(same_sysfs, first, d);
|
2010-07-20 20:33:19 +02:00
|
|
|
|
2010-07-21 05:00:29 +02:00
|
|
|
if (first)
|
2013-11-25 15:25:01 +01:00
|
|
|
hashmap_remove_and_replace(devices, d->sysfs, first->sysfs, first);
|
2010-07-21 05:00:29 +02:00
|
|
|
else
|
2013-11-25 15:25:01 +01:00
|
|
|
hashmap_remove(devices, d->sysfs);
|
2010-07-21 05:00:29 +02:00
|
|
|
|
2015-09-08 18:43:11 +02:00
|
|
|
d->sysfs = mfree(d->sysfs);
|
2010-07-20 20:33:19 +02:00
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static int device_set_sysfs(Device *d, const char *sysfs) {
|
2018-06-04 18:03:02 +02:00
|
|
|
_cleanup_free_ char *copy = NULL;
|
2015-02-27 21:55:08 +01:00
|
|
|
Device *first;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(d);
|
|
|
|
|
|
|
|
if (streq_ptr(d->sysfs, sysfs))
|
|
|
|
return 0;
|
|
|
|
|
2018-02-08 18:58:35 +01:00
|
|
|
r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &path_hash_ops);
|
2015-02-27 21:55:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
copy = strdup(sysfs);
|
|
|
|
if (!copy)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
device_unset_sysfs(d);
|
|
|
|
|
|
|
|
first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
|
|
|
|
LIST_PREPEND(same_sysfs, first, d);
|
|
|
|
|
|
|
|
r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
|
|
|
|
if (r < 0) {
|
|
|
|
LIST_REMOVE(same_sysfs, first, d);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-06-04 18:03:02 +02:00
|
|
|
d->sysfs = TAKE_PTR(copy);
|
2015-02-27 21:55:08 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-17 04:09:28 +02:00
|
|
|
static void device_init(Unit *u) {
|
|
|
|
Device *d = DEVICE(u);
|
|
|
|
|
|
|
|
assert(d);
|
2012-01-15 12:25:20 +01:00
|
|
|
assert(UNIT(d)->load_state == UNIT_STUB);
|
2010-07-17 04:09:28 +02:00
|
|
|
|
2010-07-20 20:33:19 +02:00
|
|
|
/* In contrast to all other unit types we timeout jobs waiting
|
|
|
|
* for devices by default. This is because they otherwise wait
|
2011-02-21 15:32:17 +01:00
|
|
|
* indefinitely for plugged in devices, something which cannot
|
2010-07-20 20:33:19 +02:00
|
|
|
* happen for the other units since their operations time out
|
|
|
|
* anyway. */
|
2017-04-05 14:11:12 +02:00
|
|
|
u->job_running_timeout = u->manager->default_timeout_start_usec;
|
2011-04-14 03:55:03 +02:00
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
u->ignore_on_isolate = true;
|
2010-07-17 04:09:28 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
static void device_done(Unit *u) {
|
|
|
|
Device *d = DEVICE(u);
|
2010-01-26 04:18:44 +01:00
|
|
|
|
|
|
|
assert(d);
|
2010-04-10 17:53:17 +02:00
|
|
|
|
2010-07-20 20:33:19 +02:00
|
|
|
device_unset_sysfs(d);
|
2010-04-10 17:53:17 +02:00
|
|
|
}
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
static void device_set_state(Device *d, DeviceState state) {
|
|
|
|
DeviceState old_state;
|
|
|
|
assert(d);
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
old_state = d->state;
|
|
|
|
d->state = state;
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2010-04-10 17:53:17 +02:00
|
|
|
if (state != old_state)
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
|
2010-01-29 03:18:09 +01:00
|
|
|
|
2018-06-01 19:06:19 +02:00
|
|
|
unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], 0);
|
2010-01-29 03:18:09 +01:00
|
|
|
}
|
|
|
|
|
2015-04-24 15:27:19 +02:00
|
|
|
static int device_coldplug(Unit *u) {
|
2010-01-29 03:18:09 +01:00
|
|
|
Device *d = DEVICE(u);
|
|
|
|
|
|
|
|
assert(d);
|
|
|
|
assert(d->state == DEVICE_DEAD);
|
|
|
|
|
2018-04-06 15:02:10 +02:00
|
|
|
/* This should happen only when we reexecute PID1 from an old version
|
|
|
|
* which didn't serialize d->found. In this case simply assume that the
|
|
|
|
* device was in plugged state right before we started reexecuting which
|
|
|
|
* might be a wrong assumption. */
|
|
|
|
if (d->found == DEVICE_FOUND_UDEV_DB)
|
|
|
|
d->found = DEVICE_FOUND_UDEV;
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
if (d->found & DEVICE_FOUND_UDEV)
|
|
|
|
/* If udev says the device is around, it's around */
|
2010-07-16 21:32:34 +02:00
|
|
|
device_set_state(d, DEVICE_PLUGGED);
|
2015-04-24 12:29:05 +02:00
|
|
|
else if (d->found != DEVICE_NOT_FOUND && d->deserialized_state != DEVICE_PLUGGED)
|
2015-02-27 21:55:08 +01:00
|
|
|
/* If a device is found in /proc/self/mountinfo or
|
2015-04-24 12:29:05 +02:00
|
|
|
* /proc/swaps, and was not yet announced via udev,
|
|
|
|
* it's "tentatively" around. */
|
2015-02-27 21:55:08 +01:00
|
|
|
device_set_state(d, DEVICE_TENTATIVE);
|
2010-01-29 03:18:09 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-25 15:05:00 +02:00
|
|
|
static const struct {
|
|
|
|
DeviceFound flag;
|
|
|
|
const char *name;
|
|
|
|
} device_found_map[] = {
|
|
|
|
{ DEVICE_FOUND_UDEV, "found-udev" },
|
|
|
|
{ DEVICE_FOUND_UDEV_DB, "found-udev-db" },
|
|
|
|
{ DEVICE_FOUND_MOUNT, "found-mount" },
|
|
|
|
{ DEVICE_FOUND_SWAP, "found-swap" },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int device_found_to_string_many(DeviceFound flags, char **ret) {
|
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
for (i = 0; device_found_map[i].name; i++) {
|
2018-06-04 18:03:30 +02:00
|
|
|
if (!FLAGS_SET(flags, device_found_map[i].flag))
|
2018-04-25 15:05:00 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strextend_with_separator(&s, ",", device_found_map[i].name, NULL))
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret = TAKE_PTR(s);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int device_found_from_string_many(const char *name, DeviceFound *ret) {
|
|
|
|
DeviceFound flags = 0;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *word = NULL;
|
|
|
|
DeviceFound f = 0;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
r = extract_first_word(&name, &word, ",", 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (i = 0; device_found_map[i].name; i++)
|
|
|
|
if (streq(word, device_found_map[i].name)) {
|
|
|
|
f = device_found_map[i].flag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
flags |= f;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret = flags;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
|
2018-04-25 15:05:00 +02:00
|
|
|
_cleanup_free_ char *s = NULL;
|
2015-04-24 12:29:05 +02:00
|
|
|
Device *d = DEVICE(u);
|
|
|
|
|
|
|
|
assert(u);
|
|
|
|
assert(f);
|
|
|
|
assert(fds);
|
|
|
|
|
|
|
|
unit_serialize_item(u, f, "state", device_state_to_string(d->state));
|
2018-04-25 15:05:00 +02:00
|
|
|
|
2018-06-04 18:03:57 +02:00
|
|
|
if (device_found_to_string_many(d->found, &s) >= 0)
|
|
|
|
unit_serialize_item(u, f, "found", s);
|
2015-04-24 16:14:48 +02:00
|
|
|
|
|
|
|
return 0;
|
2015-04-24 12:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
|
|
|
|
Device *d = DEVICE(u);
|
2018-04-25 15:05:00 +02:00
|
|
|
int r;
|
2015-04-24 12:29:05 +02:00
|
|
|
|
|
|
|
assert(u);
|
|
|
|
assert(key);
|
|
|
|
assert(value);
|
|
|
|
assert(fds);
|
|
|
|
|
2018-04-17 15:12:06 +02:00
|
|
|
/* The device was known at the time units were serialized but it's not
|
|
|
|
* anymore at the time units are deserialized. This happens when PID1 is
|
|
|
|
* re-executed after having switched to the new rootfs: devices were
|
|
|
|
* enumerated but udevd wasn't running yet thus the list of devices
|
|
|
|
* (handled by systemd) to initialize was empty. In such case we wait
|
|
|
|
* for the device events to be re-triggered by udev so device units are
|
|
|
|
* properly re-initialized. */
|
|
|
|
if (d->found == DEVICE_NOT_FOUND) {
|
|
|
|
assert(d->sysfs == NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
if (streq(key, "state")) {
|
|
|
|
DeviceState state;
|
|
|
|
|
|
|
|
state = device_state_from_string(value);
|
|
|
|
if (state < 0)
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(u, "Failed to parse state value: %s", value);
|
2015-04-24 12:29:05 +02:00
|
|
|
else
|
|
|
|
d->deserialized_state = state;
|
2018-04-06 15:02:10 +02:00
|
|
|
|
|
|
|
} else if (streq(key, "found")) {
|
2018-04-25 15:05:00 +02:00
|
|
|
r = device_found_from_string_many(value, &d->found);
|
|
|
|
if (r < 0)
|
2018-04-06 15:02:10 +02:00
|
|
|
log_unit_debug(u, "Failed to parse found value: %s", value);
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
} else
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(u, "Unknown serialization key: %s", key);
|
2015-04-24 12:29:05 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
static void device_dump(Unit *u, FILE *f, const char *prefix) {
|
2010-01-28 06:46:33 +01:00
|
|
|
Device *d = DEVICE(u);
|
2018-04-26 10:05:33 +02:00
|
|
|
_cleanup_free_ char *s = NULL;
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2010-01-28 06:46:33 +01:00
|
|
|
assert(d);
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2018-04-26 10:05:33 +02:00
|
|
|
(void) device_found_to_string_many(d->found, &s);
|
|
|
|
|
2010-01-23 01:52:57 +01:00
|
|
|
fprintf(f,
|
2010-01-28 06:46:33 +01:00
|
|
|
"%sDevice State: %s\n"
|
2018-04-26 10:05:33 +02:00
|
|
|
"%sSysfs Path: %s\n"
|
|
|
|
"%sFound: %s\n",
|
2010-04-21 03:27:44 +02:00
|
|
|
prefix, device_state_to_string(d->state),
|
2018-04-26 10:05:33 +02:00
|
|
|
prefix, strna(d->sysfs),
|
|
|
|
prefix, strna(s));
|
2010-01-29 03:18:09 +01:00
|
|
|
}
|
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
_pure_ static UnitActiveState device_active_state(Unit *u) {
|
2010-01-29 03:18:09 +01:00
|
|
|
assert(u);
|
|
|
|
|
|
|
|
return state_translation_table[DEVICE(u)->state];
|
2010-01-28 06:46:33 +01:00
|
|
|
}
|
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
_pure_ static const char *device_sub_state_to_string(Unit *u) {
|
2010-04-13 20:59:01 +02:00
|
|
|
assert(u);
|
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
return device_state_to_string(DEVICE(u)->state);
|
2010-04-13 20:59:01 +02:00
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
|
2014-03-06 04:57:16 +01:00
|
|
|
const char *model;
|
2015-02-27 21:55:08 +01:00
|
|
|
int r;
|
2014-03-06 04:57:16 +01:00
|
|
|
|
|
|
|
assert(u);
|
|
|
|
assert(dev);
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
|
|
|
|
if (!model)
|
|
|
|
model = udev_device_get_property_value(dev, "ID_MODEL");
|
|
|
|
|
|
|
|
if (model) {
|
|
|
|
const char *label;
|
|
|
|
|
|
|
|
/* Try to concatenate the device model string with a label, if there is one */
|
|
|
|
label = udev_device_get_property_value(dev, "ID_FS_LABEL");
|
|
|
|
if (!label)
|
|
|
|
label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
|
|
|
|
if (!label)
|
|
|
|
label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
|
|
|
|
|
|
|
|
if (label) {
|
|
|
|
_cleanup_free_ char *j;
|
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
j = strjoin(model, " ", label);
|
2018-06-04 18:04:33 +02:00
|
|
|
if (!j)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = unit_set_description(u, j);
|
2015-02-27 21:55:08 +01:00
|
|
|
} else
|
|
|
|
r = unit_set_description(u, model);
|
|
|
|
} else
|
|
|
|
r = unit_set_description(u, path);
|
|
|
|
if (r < 0)
|
2018-06-04 18:04:33 +02:00
|
|
|
return log_unit_error_errno(u, r, "Failed to set device description: %m");
|
2014-03-06 04:57:16 +01:00
|
|
|
|
2018-06-04 18:04:33 +02:00
|
|
|
return 0;
|
2014-03-06 04:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
|
2017-10-26 16:40:35 +02:00
|
|
|
const char *wants, *property;
|
2014-03-06 04:57:16 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(u);
|
|
|
|
assert(dev);
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
|
2017-10-26 16:40:35 +02:00
|
|
|
|
2014-07-31 09:28:37 +02:00
|
|
|
wants = udev_device_get_property_value(dev, property);
|
2017-10-26 16:40:35 +02:00
|
|
|
if (!wants)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (;;) {
|
2016-10-28 03:30:48 +02:00
|
|
|
_cleanup_free_ char *word = NULL, *k = NULL;
|
2014-03-06 04:57:16 +01:00
|
|
|
|
2017-10-26 16:40:35 +02:00
|
|
|
r = extract_first_word(&wants, &word, NULL, EXTRACT_QUOTES);
|
2016-10-28 03:30:48 +02:00
|
|
|
if (r == 0)
|
|
|
|
return 0;
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0)
|
2017-10-26 17:12:44 +02:00
|
|
|
return log_unit_error_errno(u, r, "Failed to parse property %s with value %s: %m", property, wants);
|
2014-03-06 04:57:16 +01:00
|
|
|
|
2017-10-26 17:12:44 +02:00
|
|
|
if (unit_name_is_valid(word, UNIT_NAME_TEMPLATE) && DEVICE(u)->sysfs) {
|
|
|
|
_cleanup_free_ char *escaped = NULL;
|
|
|
|
|
|
|
|
/* If the unit name is specified as template, then automatically fill in the sysfs path of the
|
|
|
|
* device as instance name, properly escaped. */
|
|
|
|
|
|
|
|
r = unit_name_path_escape(DEVICE(u)->sysfs, &escaped);
|
|
|
|
if (r < 0)
|
|
|
|
return log_unit_error_errno(u, r, "Failed to escape %s: %m", DEVICE(u)->sysfs);
|
|
|
|
|
|
|
|
r = unit_name_replace_instance(word, escaped, &k);
|
|
|
|
if (r < 0)
|
|
|
|
return log_unit_error_errno(u, r, "Failed to build %s instance of template %s: %m", escaped, word);
|
|
|
|
} else {
|
|
|
|
/* If this is not a template, then let's mangle it so, that it becomes a valid unit name. */
|
|
|
|
|
2018-03-21 15:26:47 +01:00
|
|
|
r = unit_name_mangle(word, UNIT_NAME_MANGLE_WARN, &k);
|
2017-10-26 17:12:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
|
|
|
|
}
|
2014-03-06 04:57:16 +01:00
|
|
|
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
|
2014-03-06 04:57:16 +01:00
|
|
|
if (r < 0)
|
2017-10-26 16:40:35 +02:00
|
|
|
return log_unit_error_errno(u, r, "Failed to add Wants= dependency: %m");
|
2014-03-06 04:57:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-25 21:29:24 +02:00
|
|
|
static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
|
2016-12-16 17:13:58 +01:00
|
|
|
const char *bound_by;
|
2017-10-25 21:29:24 +02:00
|
|
|
int r;
|
2016-12-16 17:13:58 +01:00
|
|
|
|
|
|
|
assert(d);
|
|
|
|
assert(dev);
|
|
|
|
|
|
|
|
bound_by = udev_device_get_property_value(dev, "SYSTEMD_MOUNT_DEVICE_BOUND");
|
2017-10-25 21:29:24 +02:00
|
|
|
if (bound_by) {
|
|
|
|
r = parse_boolean(bound_by);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to parse SYSTEMD_MOUNT_DEVICE_BOUND='%s' udev property of %s, ignoring: %m", bound_by, strna(d->sysfs));
|
2016-12-16 17:13:58 +01:00
|
|
|
|
2017-10-25 21:29:24 +02:00
|
|
|
d->bind_mounts = r > 0;
|
|
|
|
} else
|
|
|
|
d->bind_mounts = false;
|
|
|
|
|
|
|
|
return d->bind_mounts;
|
2016-12-16 17:13:58 +01:00
|
|
|
}
|
|
|
|
|
2018-06-04 18:05:09 +02:00
|
|
|
static void device_upgrade_mount_deps(Unit *u) {
|
2016-12-16 17:13:58 +01:00
|
|
|
Unit *other;
|
|
|
|
Iterator i;
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
void *v;
|
2016-12-16 17:13:58 +01:00
|
|
|
int r;
|
|
|
|
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
/* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */
|
|
|
|
|
|
|
|
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRED_BY], i) {
|
2016-12-16 17:13:58 +01:00
|
|
|
if (other->type != UNIT_MOUNT)
|
|
|
|
continue;
|
|
|
|
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV);
|
2016-12-16 17:13:58 +01:00
|
|
|
if (r < 0)
|
2018-06-04 18:05:09 +02:00
|
|
|
log_unit_warning_errno(u, r, "Failed to add BindsTo= dependency between device and mount unit, ignoring: %m");
|
2016-12-16 17:13:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
|
|
|
|
_cleanup_free_ char *e = NULL;
|
2015-05-17 15:07:47 +02:00
|
|
|
const char *sysfs = NULL;
|
2010-01-28 06:46:33 +01:00
|
|
|
Unit *u = NULL;
|
|
|
|
bool delete;
|
2014-03-06 04:57:16 +01:00
|
|
|
int r;
|
2010-01-28 06:46:33 +01:00
|
|
|
|
|
|
|
assert(m);
|
2014-03-06 04:57:16 +01:00
|
|
|
assert(path);
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
if (dev) {
|
|
|
|
sysfs = udev_device_get_syspath(dev);
|
|
|
|
if (!sysfs)
|
|
|
|
return 0;
|
|
|
|
}
|
2010-04-08 00:53:21 +02:00
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
r = unit_name_from_path(path, ".device", &e);
|
|
|
|
if (r < 0)
|
2015-05-06 19:56:29 +02:00
|
|
|
return log_error_errno(r, "Failed to generate unit name from device path: %m");
|
2015-02-27 21:55:08 +01:00
|
|
|
|
|
|
|
u = manager_get_unit(m, e);
|
2017-10-26 16:41:06 +02:00
|
|
|
if (u) {
|
|
|
|
/* The device unit can still be present even if the device was unplugged: a mount unit can reference it hence
|
|
|
|
* preventing the GC to have garbaged it. That's desired since the device unit may have a dependency on the
|
|
|
|
* mount unit which was added during the loading of the later. */
|
|
|
|
if (dev && DEVICE(u)->state == DEVICE_PLUGGED) {
|
|
|
|
|
|
|
|
/* This unit is in plugged state: we're sure it's attached to a device. */
|
|
|
|
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
|
|
|
|
log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
|
|
|
|
e, DEVICE(u)->sysfs, sysfs);
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
2016-01-22 07:18:19 +01:00
|
|
|
}
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2017-10-26 16:41:06 +02:00
|
|
|
delete = false;
|
|
|
|
|
|
|
|
/* Let's remove all dependencies generated due to udev properties. We'll readd whatever is configured
|
|
|
|
* now below. */
|
|
|
|
unit_remove_dependencies(u, UNIT_DEPENDENCY_UDEV);
|
|
|
|
} else {
|
2010-04-08 04:34:21 +02:00
|
|
|
delete = true;
|
|
|
|
|
2016-10-25 00:29:05 +02:00
|
|
|
r = unit_new_for_name(m, sizeof(Device), e, &u);
|
2012-01-15 10:53:49 +01:00
|
|
|
if (r < 0)
|
2010-01-28 06:46:33 +01:00
|
|
|
goto fail;
|
|
|
|
|
2010-08-06 04:17:51 +02:00
|
|
|
unit_add_to_load_queue(u);
|
2017-10-26 16:41:06 +02:00
|
|
|
}
|
2010-08-06 04:17:51 +02:00
|
|
|
|
|
|
|
/* If this was created via some dependency and has not
|
|
|
|
* actually been seen yet ->sysfs will not be
|
|
|
|
* initialized. Hence initialize it if necessary. */
|
2015-05-17 15:07:47 +02:00
|
|
|
if (sysfs) {
|
|
|
|
r = device_set_sysfs(DEVICE(u), sysfs);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2010-08-06 04:17:51 +02:00
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
(void) device_update_description(u, dev, path);
|
2010-04-08 04:34:21 +02:00
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
/* The additional systemd udev properties we only interpret
|
|
|
|
* for the main object */
|
|
|
|
if (main)
|
|
|
|
(void) device_add_udev_wants(u, dev);
|
|
|
|
}
|
2010-01-28 06:46:33 +01:00
|
|
|
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
/* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
|
|
|
|
* before the device appears on its radar. In this case the device unit is partially initialized and includes
|
|
|
|
* the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
|
2017-10-25 21:29:24 +02:00
|
|
|
if (dev && device_is_bound_by_mounts(DEVICE(u), dev))
|
2016-12-16 17:13:58 +01:00
|
|
|
device_upgrade_mount_deps(u);
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2017-10-26 16:41:06 +02:00
|
|
|
/* Note that this won't dispatch the load queue, the caller has to do that if needed and appropriate */
|
2013-11-25 15:25:01 +01:00
|
|
|
|
2010-02-05 00:38:41 +01:00
|
|
|
unit_add_to_dbus_queue(u);
|
2010-01-28 06:46:33 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_warning_errno(u, r, "Failed to set up device unit: %m");
|
2010-07-13 02:17:26 +02:00
|
|
|
|
2016-11-28 19:41:20 +01:00
|
|
|
if (delete)
|
2010-01-28 06:46:33 +01:00
|
|
|
unit_free(u);
|
2010-07-13 02:17:26 +02:00
|
|
|
|
2010-01-28 06:46:33 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static int device_process_new(Manager *m, struct udev_device *dev) {
|
2013-11-25 15:25:01 +01:00
|
|
|
const char *sysfs, *dn, *alias;
|
2010-07-20 20:33:19 +02:00
|
|
|
struct udev_list_entry *item = NULL, *first = NULL;
|
2013-04-12 11:56:27 +02:00
|
|
|
int r;
|
2010-07-20 20:33:19 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
sysfs = udev_device_get_syspath(dev);
|
|
|
|
if (!sysfs)
|
2013-11-25 15:25:01 +01:00
|
|
|
return 0;
|
2010-07-20 20:33:19 +02:00
|
|
|
|
|
|
|
/* Add the main unit named after the sysfs path */
|
2015-02-27 21:55:08 +01:00
|
|
|
r = device_setup_unit(m, dev, sysfs, true);
|
2013-04-12 11:56:27 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-07-20 20:33:19 +02:00
|
|
|
|
|
|
|
/* Add an additional unit for the device node */
|
2013-11-25 15:25:01 +01:00
|
|
|
dn = udev_device_get_devnode(dev);
|
|
|
|
if (dn)
|
2015-02-27 21:55:08 +01:00
|
|
|
(void) device_setup_unit(m, dev, dn, false);
|
2010-07-20 20:33:19 +02:00
|
|
|
|
|
|
|
/* Add additional units for all symlinks */
|
|
|
|
first = udev_device_get_devlinks_list_entry(dev);
|
|
|
|
udev_list_entry_foreach(item, first) {
|
|
|
|
const char *p;
|
2010-08-20 04:04:05 +02:00
|
|
|
struct stat st;
|
2010-07-20 20:33:19 +02:00
|
|
|
|
|
|
|
/* Don't bother with the /dev/block links */
|
|
|
|
p = udev_list_entry_get_name(item);
|
|
|
|
|
|
|
|
if (path_startswith(p, "/dev/block/") ||
|
|
|
|
path_startswith(p, "/dev/char/"))
|
|
|
|
continue;
|
|
|
|
|
2010-08-20 04:04:05 +02:00
|
|
|
/* Verify that the symlink in the FS actually belongs
|
|
|
|
* to this device. This is useful to deal with
|
|
|
|
* conflicting devices, e.g. when two disks want the
|
|
|
|
* same /dev/disk/by-label/xxx link because they have
|
|
|
|
* the same label. We want to make sure that the same
|
|
|
|
* device that won the symlink wins in systemd, so we
|
2014-12-10 20:00:08 +01:00
|
|
|
* check the device node major/minor */
|
2010-08-20 04:04:05 +02:00
|
|
|
if (stat(p, &st) >= 0)
|
|
|
|
if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
|
|
|
|
st.st_rdev != udev_device_get_devnum(dev))
|
|
|
|
continue;
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
(void) device_setup_unit(m, dev, p, false);
|
2010-07-20 20:33:19 +02:00
|
|
|
}
|
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
/* Add additional units for all explicitly configured
|
|
|
|
* aliases */
|
|
|
|
alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
|
2016-10-28 03:30:48 +02:00
|
|
|
for (;;) {
|
2016-12-06 00:07:34 +01:00
|
|
|
_cleanup_free_ char *word = NULL;
|
2010-07-20 20:33:19 +02:00
|
|
|
|
2016-10-28 03:30:48 +02:00
|
|
|
r = extract_first_word(&alias, &word, NULL, EXTRACT_QUOTES);
|
|
|
|
if (r == 0)
|
|
|
|
return 0;
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0)
|
|
|
|
return log_warning_errno(r, "Failed to add parse SYSTEMD_ALIAS for %s: %m", sysfs);
|
2013-11-25 15:25:01 +01:00
|
|
|
|
2016-10-28 03:30:48 +02:00
|
|
|
if (path_is_absolute(word))
|
|
|
|
(void) device_setup_unit(m, dev, word, false);
|
|
|
|
else
|
|
|
|
log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, word);
|
2010-07-20 20:33:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
|
2015-04-24 12:29:05 +02:00
|
|
|
DeviceFound n, previous;
|
2015-02-27 21:55:08 +01:00
|
|
|
|
|
|
|
assert(d);
|
|
|
|
|
|
|
|
n = add ? (d->found | found) : (d->found & ~found);
|
|
|
|
if (n == d->found)
|
|
|
|
return;
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
previous = d->found;
|
2015-02-27 21:55:08 +01:00
|
|
|
d->found = n;
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
if (!now)
|
|
|
|
return;
|
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
|
|
|
|
if (previous == DEVICE_NOT_FOUND && d->found != DEVICE_NOT_FOUND)
|
|
|
|
(void) unit_acquire_invocation_id(UNIT(d));
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
if (d->found & DEVICE_FOUND_UDEV)
|
|
|
|
/* When the device is known to udev we consider it
|
|
|
|
* plugged. */
|
|
|
|
device_set_state(d, DEVICE_PLUGGED);
|
|
|
|
else if (d->found != DEVICE_NOT_FOUND && (previous & DEVICE_FOUND_UDEV) == 0)
|
|
|
|
/* If the device has not been seen by udev yet, but is
|
|
|
|
* now referenced by the kernel, then we assume the
|
|
|
|
* kernel knows it now, and udev might soon too. */
|
|
|
|
device_set_state(d, DEVICE_TENTATIVE);
|
2017-06-23 02:29:15 +02:00
|
|
|
else {
|
2015-04-24 12:29:05 +02:00
|
|
|
/* If nobody sees the device, or if the device was
|
|
|
|
* previously seen by udev and now is only referenced
|
|
|
|
* from the kernel, then we consider the device is
|
|
|
|
* gone, the kernel just hasn't noticed it yet. */
|
2017-06-23 02:29:15 +02:00
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
device_set_state(d, DEVICE_DEAD);
|
2017-06-23 02:29:15 +02:00
|
|
|
device_unset_sysfs(d);
|
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
|
2017-08-30 17:16:16 +02:00
|
|
|
Device *d, *l, *n;
|
2010-01-28 06:46:33 +01:00
|
|
|
|
|
|
|
assert(m);
|
2015-02-27 21:55:08 +01:00
|
|
|
assert(sysfs);
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
if (found == DEVICE_NOT_FOUND)
|
|
|
|
return 0;
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
l = hashmap_get(m->devices_by_sysfs, sysfs);
|
2017-08-30 17:16:16 +02:00
|
|
|
LIST_FOREACH_SAFE(same_sysfs, d, n, l)
|
2015-02-27 21:55:08 +01:00
|
|
|
device_update_found_one(d, add, found, now);
|
|
|
|
|
|
|
|
return 0;
|
2010-01-28 06:46:33 +01:00
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
|
|
|
|
_cleanup_free_ char *e = NULL;
|
|
|
|
Unit *u;
|
2015-04-30 20:21:00 +02:00
|
|
|
int r;
|
2010-01-29 06:45:59 +01:00
|
|
|
|
|
|
|
assert(m);
|
2015-02-27 21:55:08 +01:00
|
|
|
assert(path);
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
if (found == DEVICE_NOT_FOUND)
|
|
|
|
return 0;
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
r = unit_name_from_path(path, ".device", &e);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to generate unit name from device path: %m");
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
u = manager_get_unit(m, e);
|
|
|
|
if (!u)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
device_update_found_one(DEVICE(u), add, found, now);
|
2010-01-29 06:45:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
static bool device_is_ready(struct udev_device *dev) {
|
|
|
|
const char *ready;
|
|
|
|
|
|
|
|
assert(dev);
|
|
|
|
|
|
|
|
ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
|
|
|
|
if (!ready)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return parse_boolean(ready) != 0;
|
|
|
|
}
|
|
|
|
|
2010-07-21 05:00:29 +02:00
|
|
|
static Unit *device_following(Unit *u) {
|
|
|
|
Device *d = DEVICE(u);
|
|
|
|
Device *other, *first = NULL;
|
|
|
|
|
|
|
|
assert(d);
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (startswith(u->id, "sys-"))
|
2010-07-21 05:00:29 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Make everybody follow the unit that's named after the sysfs path */
|
|
|
|
for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
|
2012-01-15 12:25:20 +01:00
|
|
|
if (startswith(UNIT(other)->id, "sys-"))
|
2010-07-21 05:00:29 +02:00
|
|
|
return UNIT(other);
|
|
|
|
|
|
|
|
for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
|
2012-01-15 12:25:20 +01:00
|
|
|
if (startswith(UNIT(other)->id, "sys-"))
|
2010-07-21 05:00:29 +02:00
|
|
|
return UNIT(other);
|
|
|
|
|
|
|
|
first = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UNIT(first);
|
|
|
|
}
|
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
static int device_following_set(Unit *u, Set **_set) {
|
|
|
|
Device *d = DEVICE(u), *other;
|
2018-05-14 07:13:57 +02:00
|
|
|
_cleanup_set_free_ Set *set = NULL;
|
2010-11-14 23:47:53 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(d);
|
2013-11-25 15:25:01 +01:00
|
|
|
assert(_set);
|
2010-11-14 23:47:53 +01:00
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
if (LIST_JUST_US(same_sysfs, d)) {
|
|
|
|
*_set = NULL;
|
2010-11-14 23:47:53 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
set = set_new(NULL);
|
2013-11-25 15:25:01 +01:00
|
|
|
if (!set)
|
2010-11-14 23:47:53 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
LIST_FOREACH_AFTER(same_sysfs, other, d) {
|
|
|
|
r = set_put(set, other);
|
|
|
|
if (r < 0)
|
2018-05-11 18:43:40 +02:00
|
|
|
return r;
|
2013-11-25 15:25:01 +01:00
|
|
|
}
|
2010-11-14 23:47:53 +01:00
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
|
|
|
|
r = set_put(set, other);
|
|
|
|
if (r < 0)
|
2018-05-11 18:43:40 +02:00
|
|
|
return r;
|
2013-11-25 15:25:01 +01:00
|
|
|
}
|
2010-11-14 23:47:53 +01:00
|
|
|
|
2018-05-11 18:43:40 +02:00
|
|
|
*_set = TAKE_PTR(set);
|
2010-11-14 23:47:53 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-01-28 06:46:33 +01:00
|
|
|
static void device_shutdown(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
m->udev_event_source = sd_event_source_unref(m->udev_event_source);
|
2018-04-06 08:45:13 +02:00
|
|
|
m->udev_monitor = udev_monitor_unref(m->udev_monitor);
|
2015-09-09 23:12:07 +02:00
|
|
|
m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
|
2010-01-28 06:46:33 +01:00
|
|
|
}
|
|
|
|
|
2015-11-10 20:36:37 +01:00
|
|
|
static void device_enumerate(Manager *m) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
|
2010-01-28 06:46:33 +01:00
|
|
|
struct udev_list_entry *item = NULL, *first = NULL;
|
2013-11-19 21:12:59 +01:00
|
|
|
int r;
|
2010-01-28 06:46:33 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2013-11-25 21:08:39 +01:00
|
|
|
if (!m->udev_monitor) {
|
2013-11-19 21:12:59 +01:00
|
|
|
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
|
|
|
|
if (!m->udev_monitor) {
|
2015-11-10 20:36:37 +01:00
|
|
|
log_oom();
|
2010-04-21 03:27:44 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2011-01-08 02:30:07 +01:00
|
|
|
/* This will fail if we are unprivileged, but that
|
|
|
|
* should not matter much, as user instances won't run
|
|
|
|
* during boot. */
|
2015-03-14 03:21:41 +01:00
|
|
|
(void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
|
2010-11-26 04:51:30 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to add udev tag match: %m");
|
2010-05-22 01:00:28 +02:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2010-05-22 01:00:28 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = udev_monitor_enable_receiving(m->udev_monitor);
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to enable udev event reception: %m");
|
2010-04-21 03:27:44 +02:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to watch udev file descriptor: %m");
|
2013-11-19 21:12:59 +01:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2015-04-29 16:05:32 +02:00
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->udev_event_source, "device");
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
e = udev_enumerate_new(m->udev);
|
|
|
|
if (!e) {
|
2015-11-10 20:36:37 +01:00
|
|
|
log_oom();
|
2010-04-15 06:19:54 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
2013-11-19 21:12:59 +01:00
|
|
|
|
|
|
|
r = udev_enumerate_add_match_tag(e, "systemd");
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to create udev tag enumeration: %m");
|
2010-05-22 01:00:28 +02:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2013-12-18 17:12:15 +01:00
|
|
|
r = udev_enumerate_add_match_is_initialized(e);
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to install initialization match into enumeration: %m");
|
2013-12-18 17:12:15 +01:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2013-12-18 17:12:15 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = udev_enumerate_scan_devices(e);
|
2015-11-10 20:36:37 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to enumerate devices: %m");
|
2010-04-15 06:19:54 +02:00
|
|
|
goto fail;
|
2015-11-10 20:36:37 +01:00
|
|
|
}
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2010-04-15 06:19:54 +02:00
|
|
|
first = udev_enumerate_get_list_entry(e);
|
2015-02-27 21:55:08 +01:00
|
|
|
udev_list_entry_foreach(item, first) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
|
2015-02-27 21:55:08 +01:00
|
|
|
const char *sysfs;
|
|
|
|
|
|
|
|
sysfs = udev_list_entry_get_name(item);
|
|
|
|
|
|
|
|
dev = udev_device_new_from_syspath(m->udev, sysfs);
|
|
|
|
if (!dev) {
|
|
|
|
log_oom();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!device_is_ready(dev))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
(void) device_process_new(m, dev);
|
|
|
|
|
2018-04-06 15:02:10 +02:00
|
|
|
device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV_DB, false);
|
2015-02-27 21:55:08 +01:00
|
|
|
}
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2015-11-10 20:36:37 +01:00
|
|
|
return;
|
2010-01-28 06:46:33 +01:00
|
|
|
|
|
|
|
fail:
|
|
|
|
device_shutdown(m);
|
2010-01-23 01:52:57 +01:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
|
2013-11-19 21:12:59 +01:00
|
|
|
Manager *m = userdata;
|
2015-02-27 21:55:08 +01:00
|
|
|
const char *action, *sysfs;
|
2013-11-19 21:12:59 +01:00
|
|
|
int r;
|
2010-01-29 06:45:59 +01:00
|
|
|
|
|
|
|
assert(m);
|
2010-11-26 04:51:30 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
if (revents != EPOLLIN) {
|
2010-11-26 04:51:30 +01:00
|
|
|
static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
|
|
|
|
|
2018-05-11 11:16:52 +02:00
|
|
|
if (ratelimit_below(&limit))
|
2018-04-24 13:50:46 +02:00
|
|
|
log_warning("Failed to get udev event");
|
2013-11-19 21:12:59 +01:00
|
|
|
if (!(revents & EPOLLIN))
|
|
|
|
return 0;
|
2010-11-26 04:51:30 +01:00
|
|
|
}
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
/*
|
|
|
|
* libudev might filter-out devices which pass the bloom
|
|
|
|
* filter, so getting NULL here is not necessarily an error.
|
|
|
|
*/
|
|
|
|
dev = udev_monitor_receive_device(m->udev_monitor);
|
|
|
|
if (!dev)
|
|
|
|
return 0;
|
2010-01-29 06:45:59 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
sysfs = udev_device_get_syspath(dev);
|
|
|
|
if (!sysfs) {
|
|
|
|
log_error("Failed to get udev sys path.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
action = udev_device_get_action(dev);
|
|
|
|
if (!action) {
|
2010-01-29 06:45:59 +01:00
|
|
|
log_error("Failed to get udev action string.");
|
2013-11-19 21:12:59 +01:00
|
|
|
return 0;
|
2010-01-29 06:45:59 +01:00
|
|
|
}
|
|
|
|
|
2017-11-10 17:00:32 +01:00
|
|
|
if (streq(action, "change")) {
|
|
|
|
Unit *u;
|
2018-01-06 22:55:22 +01:00
|
|
|
Device *d, *l, *n;
|
2017-11-10 17:00:32 +01:00
|
|
|
|
2018-01-06 22:55:22 +01:00
|
|
|
l = hashmap_get(m->devices_by_sysfs, sysfs);
|
|
|
|
LIST_FOREACH_SAFE(same_sysfs, d, n, l) {
|
|
|
|
u = &d->meta;
|
2017-11-10 17:00:32 +01:00
|
|
|
if (u && UNIT_VTABLE(u)->active_state(u) == UNIT_ACTIVE) {
|
|
|
|
r = manager_propagate_reload(m, u, JOB_REPLACE, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
log_error_errno(r, "Failed to propagate reload: %m");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A change event can signal that a device is becoming ready, in particular if
|
|
|
|
* the device is using the SYSTEMD_READY logic in udev
|
|
|
|
* so we need to reach the else block of the follwing if, even for change events */
|
2017-09-15 09:21:49 +02:00
|
|
|
if (streq(action, "remove")) {
|
2015-02-27 21:55:08 +01:00
|
|
|
r = swap_process_device_remove(m, dev);
|
2013-11-25 21:08:39 +01:00
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to process swap device remove event: %m");
|
2013-11-25 21:08:39 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
/* If we get notified that a device was removed by
|
|
|
|
* udev, then it's completely gone, hence unset all
|
|
|
|
* found bits */
|
|
|
|
device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
|
2013-11-25 15:25:01 +01:00
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
} else if (device_is_ready(dev)) {
|
|
|
|
|
|
|
|
(void) device_process_new(m, dev);
|
|
|
|
|
|
|
|
r = swap_process_device_new(m, dev);
|
2013-11-25 21:08:39 +01:00
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to process swap device new event: %m");
|
2013-11-25 21:08:39 +01:00
|
|
|
|
2013-11-25 15:25:01 +01:00
|
|
|
manager_dispatch_load_queue(m);
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
/* The device is found now, set the udev found bit */
|
|
|
|
device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* The device is nominally around, but not ready for
|
|
|
|
* us. Hence unset the udev bit, but leave the rest
|
|
|
|
* around. */
|
|
|
|
|
|
|
|
device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
|
2010-01-29 06:45:59 +01:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
return 0;
|
2010-01-29 06:45:59 +01:00
|
|
|
}
|
|
|
|
|
2015-04-30 01:29:00 +02:00
|
|
|
static bool device_supported(void) {
|
2014-12-12 21:05:32 +01:00
|
|
|
static int read_only = -1;
|
|
|
|
|
|
|
|
/* If /sys is read-only we don't support device units, and any
|
|
|
|
* attempts to start one should fail immediately. */
|
|
|
|
|
|
|
|
if (read_only < 0)
|
|
|
|
read_only = path_is_read_only_fs("/sys");
|
|
|
|
|
|
|
|
return read_only <= 0;
|
|
|
|
}
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
|
2015-02-27 21:55:08 +01:00
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(node);
|
|
|
|
|
2015-05-21 20:43:21 +02:00
|
|
|
if (!device_supported())
|
|
|
|
return 0;
|
|
|
|
|
2015-02-27 21:55:08 +01:00
|
|
|
/* This is called whenever we find a device referenced in
|
|
|
|
* /proc/swaps or /proc/self/mounts. Such a device might be
|
|
|
|
* mounted/enabled at a time where udev has not finished
|
|
|
|
* probing it yet, and we thus haven't learned about it
|
|
|
|
* yet. In this case we will set the device unit to
|
|
|
|
* "tentative" state. */
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
if (!path_startswith(node, "/dev"))
|
|
|
|
return 0;
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
/* We make an extra check here, if the device node
|
|
|
|
* actually exists. If it's missing, then this is an
|
|
|
|
* indication that device was unplugged but is still
|
|
|
|
* referenced in /proc/swaps or
|
|
|
|
* /proc/self/mountinfo. Note that this check doesn't
|
|
|
|
* really cover all cases where a device might be gone
|
|
|
|
* away, since drives that can have a medium inserted
|
|
|
|
* will still have a device node even when the medium
|
|
|
|
* is not there... */
|
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
if (stat(node, &st) >= 0) {
|
|
|
|
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
|
2015-02-27 21:55:08 +01:00
|
|
|
return 0;
|
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
|
|
|
|
if (!dev && errno != ENOENT)
|
|
|
|
return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
|
2015-02-27 21:55:08 +01:00
|
|
|
|
2015-05-17 15:07:47 +02:00
|
|
|
} else if (errno != ENOENT)
|
|
|
|
return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
|
2015-02-27 21:55:08 +01:00
|
|
|
|
|
|
|
/* If the device is known in the kernel and newly
|
|
|
|
* appeared, then we'll create a device unit for it,
|
|
|
|
* under the name referenced in /proc/swaps or
|
|
|
|
* /proc/self/mountinfo. */
|
|
|
|
|
|
|
|
(void) device_setup_unit(m, dev, node, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the device unit's state, should it exist */
|
|
|
|
return device_update_found_by_name(m, node, add, found, now);
|
|
|
|
}
|
|
|
|
|
2016-12-16 17:13:58 +01:00
|
|
|
bool device_shall_be_bound_by(Unit *device, Unit *u) {
|
|
|
|
|
|
|
|
if (u->type != UNIT_MOUNT)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return DEVICE(device)->bind_mounts;
|
|
|
|
}
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
const UnitVTable device_vtable = {
|
2012-01-15 10:53:49 +01:00
|
|
|
.object_size = sizeof(Device),
|
2011-08-01 00:43:05 +02:00
|
|
|
.sections =
|
|
|
|
"Unit\0"
|
|
|
|
"Device\0"
|
|
|
|
"Install\0",
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
.gc_jobs = true,
|
|
|
|
|
2010-07-17 04:09:28 +02:00
|
|
|
.init = device_init,
|
2010-01-26 04:18:44 +01:00
|
|
|
.done = device_done,
|
2013-11-19 21:12:59 +01:00
|
|
|
.load = unit_load_fragment_and_dropin_optional,
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
.coldplug = device_coldplug,
|
|
|
|
|
2015-04-24 12:29:05 +02:00
|
|
|
.serialize = device_serialize,
|
|
|
|
.deserialize_item = device_deserialize_item,
|
|
|
|
|
2010-01-23 01:52:57 +01:00
|
|
|
.dump = device_dump,
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
.active_state = device_active_state,
|
2010-04-13 20:59:01 +02:00
|
|
|
.sub_state_to_string = device_sub_state_to_string,
|
2010-01-28 06:46:33 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
.bus_vtable = bus_device_vtable,
|
2010-04-18 03:08:16 +02:00
|
|
|
|
2010-07-21 05:00:29 +02:00
|
|
|
.following = device_following,
|
2010-11-14 23:47:53 +01:00
|
|
|
.following_set = device_following_set,
|
2010-07-21 05:00:29 +02:00
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
.enumerate = device_enumerate,
|
2012-05-13 18:18:54 +02:00
|
|
|
.shutdown = device_shutdown,
|
2014-12-12 21:05:32 +01:00
|
|
|
.supported = device_supported,
|
2012-05-13 18:18:54 +02:00
|
|
|
|
|
|
|
.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.",
|
|
|
|
},
|
|
|
|
},
|
2010-01-23 01:52:57 +01:00
|
|
|
};
|