1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/epoll.h>
30 #include "unit-name.h"
31 #include "dbus-device.h"
33 static const UnitActiveState state_translation_table
[_DEVICE_STATE_MAX
] = {
34 [DEVICE_DEAD
] = UNIT_INACTIVE
,
35 [DEVICE_AVAILABLE
] = UNIT_ACTIVE
38 static void device_done(Unit
*u
) {
39 Device
*d
= DEVICE(u
);
47 static void device_set_state(Device
*d
, DeviceState state
) {
48 DeviceState old_state
;
54 if (state
!= old_state
)
55 log_debug("%s changed %s -> %s",
57 device_state_to_string(old_state
),
58 device_state_to_string(state
));
60 unit_notify(UNIT(d
), state_translation_table
[old_state
], state_translation_table
[state
]);
63 static int device_coldplug(Unit
*u
) {
64 Device
*d
= DEVICE(u
);
67 assert(d
->state
== DEVICE_DEAD
);
70 device_set_state(d
, DEVICE_AVAILABLE
);
75 static void device_dump(Unit
*u
, FILE *f
, const char *prefix
) {
76 Device
*d
= DEVICE(u
);
81 "%sDevice State: %s\n"
83 prefix
, device_state_to_string(d
->state
),
84 prefix
, strna(d
->sysfs
));
87 static UnitActiveState
device_active_state(Unit
*u
) {
90 return state_translation_table
[DEVICE(u
)->state
];
93 static const char *device_sub_state_to_string(Unit
*u
) {
96 return device_state_to_string(DEVICE(u
)->state
);
99 static int device_add_escaped_name(Unit
*u
, const char *dn
, bool make_id
) {
105 assert(dn
[0] == '/');
107 if (!(e
= unit_name_from_path(dn
, ".device")))
110 r
= unit_add_name(u
, e
);
112 if (r
>= 0 && make_id
)
113 unit_choose_id(u
, e
);
117 if (r
< 0 && r
!= -EEXIST
)
123 static int device_find_escape_name(Manager
*m
, const char *dn
, Unit
**_u
) {
129 assert(dn
[0] == '/');
132 if (!(e
= unit_name_from_path(dn
, ".device")))
135 u
= manager_get_unit(m
, e
);
146 static int device_process_new_device(Manager
*m
, struct udev_device
*dev
, bool update_state
) {
147 const char *dn
, *wants
, *sysfs
, *expose
, *model
, *alias
;
153 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
158 if (!(sysfs
= udev_device_get_syspath(dev
)))
161 if (!(expose
= udev_device_get_property_value(dev
, "SYSTEMD_EXPOSE")))
164 if ((b
= parse_boolean(expose
)) < 0) {
165 log_error("Failed to parse SYSTEMD_EXPOSE udev property for device %s: %s", sysfs
, expose
);
172 /* Check whether this entry is even relevant for us. */
173 dn
= udev_device_get_devnode(dev
);
174 wants
= udev_device_get_property_value(dev
, "SYSTEMD_WANTS");
175 alias
= udev_device_get_property_value(dev
, "SYSTEMD_ALIAS");
177 /* We allow exactly one alias to be configured a this time and
178 * it must be a path */
180 if (alias
&& !is_path(alias
)) {
181 log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs
, alias
);
185 if ((r
= device_find_escape_name(m
, sysfs
, &u
)) < 0)
189 if ((r
= device_find_escape_name(m
, dn
, &u
)) < 0)
193 first
= udev_device_get_devlinks_list_entry(dev
);
194 udev_list_entry_foreach(item
, first
) {
195 if ((r
= device_find_escape_name(m
, udev_list_entry_get_name(item
), &u
)) < 0)
204 if ((r
= device_find_escape_name(m
, alias
, &u
)) < 0)
207 /* FIXME: this needs proper merging */
209 assert((r
> 0) == !!u
);
211 /* If this is a different unit, then let's not merge things */
212 if (u
&& DEVICE(u
)->sysfs
&& !path_equal(DEVICE(u
)->sysfs
, sysfs
))
218 if (!(u
= unit_new(m
)))
221 if ((r
= device_add_escaped_name(u
, sysfs
, true)) < 0)
224 unit_add_to_load_queue(u
);
228 if (!(DEVICE(u
)->sysfs
))
229 if (!(DEVICE(u
)->sysfs
= strdup(sysfs
))) {
235 if ((r
= device_add_escaped_name(u
, alias
, true)) < 0)
239 if ((r
= device_add_escaped_name(u
, dn
, true)) < 0)
242 first
= udev_device_get_devlinks_list_entry(dev
);
243 udev_list_entry_foreach(item
, first
)
244 if ((r
= device_add_escaped_name(u
, udev_list_entry_get_name(item
), false)) < 0)
247 if ((model
= udev_device_get_property_value(dev
, "ID_MODEL_FROM_DATABASE")) ||
248 (model
= udev_device_get_property_value(dev
, "ID_MODEL"))) {
249 if ((r
= unit_set_description(u
, model
)) < 0)
252 if ((r
= unit_set_description(u
, dn
)) < 0)
256 FOREACH_WORD(w
, l
, wants
, state
) {
259 if (!(e
= strndup(w
, l
))) {
264 r
= unit_add_dependency_by_name(u
, UNIT_WANTS
, NULL
, e
, true);
273 manager_dispatch_load_queue(u
->meta
.manager
);
274 device_set_state(DEVICE(u
), DEVICE_AVAILABLE
);
277 unit_add_to_dbus_queue(u
);
287 static int device_process_path(Manager
*m
, const char *path
, bool update_state
) {
289 struct udev_device
*dev
;
294 if (!(dev
= udev_device_new_from_syspath(m
->udev
, path
))) {
295 log_warning("Failed to get udev device object from udev for path %s.", path
);
299 r
= device_process_new_device(m
, dev
, update_state
);
300 udev_device_unref(dev
);
304 static int device_process_removed_device(Manager
*m
, struct udev_device
*dev
) {
313 if (!(sysfs
= udev_device_get_syspath(dev
)))
316 assert(sysfs
[0] == '/');
317 if (!(e
= unit_name_from_path(sysfs
, ".device")))
320 u
= manager_get_unit(m
, e
);
330 device_set_state(d
, DEVICE_DEAD
);
334 static void device_shutdown(Manager
*m
) {
337 if (m
->udev_monitor
) {
338 udev_monitor_unref(m
->udev_monitor
);
339 m
->udev_monitor
= NULL
;
348 static int device_enumerate(Manager
*m
) {
349 struct epoll_event ev
;
351 struct udev_enumerate
*e
= NULL
;
352 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
357 if (!(m
->udev
= udev_new()))
360 if (!(m
->udev_monitor
= udev_monitor_new_from_netlink(m
->udev
, "udev"))) {
365 if (udev_monitor_enable_receiving(m
->udev_monitor
) < 0) {
370 m
->udev_watch
.type
= WATCH_UDEV
;
371 m
->udev_watch
.fd
= udev_monitor_get_fd(m
->udev_monitor
);
375 ev
.data
.ptr
= &m
->udev_watch
;
377 if (epoll_ctl(m
->epoll_fd
, EPOLL_CTL_ADD
, m
->udev_watch
.fd
, &ev
) < 0)
381 if (!(e
= udev_enumerate_new(m
->udev
))) {
386 if (udev_enumerate_scan_devices(e
) < 0) {
391 first
= udev_enumerate_get_list_entry(e
);
392 udev_list_entry_foreach(item
, first
)
393 device_process_path(m
, udev_list_entry_get_name(item
), false);
395 udev_enumerate_unref(e
);
400 udev_enumerate_unref(e
);
406 void device_fd_event(Manager
*m
, int events
) {
407 struct udev_device
*dev
;
412 assert(events
== EPOLLIN
);
414 if (!(dev
= udev_monitor_receive_device(m
->udev_monitor
))) {
415 log_error("Failed to receive device.");
419 if (!(action
= udev_device_get_action(dev
))) {
420 log_error("Failed to get udev action string.");
424 if (streq(action
, "remove")) {
425 if ((r
= device_process_removed_device(m
, dev
)) < 0) {
426 log_error("Failed to process udev device event: %s", strerror(-r
));
430 if ((r
= device_process_new_device(m
, dev
, true)) < 0) {
431 log_error("Failed to process udev device event: %s", strerror(-r
));
437 udev_device_unref(dev
);
440 static const char* const device_state_table
[_DEVICE_STATE_MAX
] = {
441 [DEVICE_DEAD
] = "dead",
442 [DEVICE_AVAILABLE
] = "available"
445 DEFINE_STRING_TABLE_LOOKUP(device_state
, DeviceState
);
447 const UnitVTable device_vtable
= {
451 .no_instances
= true,
452 .no_snapshots
= true,
455 .load
= unit_load_fragment_and_dropin_optional
,
457 .coldplug
= device_coldplug
,
461 .active_state
= device_active_state
,
462 .sub_state_to_string
= device_sub_state_to_string
,
464 .bus_message_handler
= bus_device_message_handler
,
466 .enumerate
= device_enumerate
,
467 .shutdown
= device_shutdown