1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
12 static const UnitActiveState state_translation_table
[_DEVICE_STATE_MAX
] = {
13 [DEVICE_DEAD
] = UNIT_INACTIVE
,
14 [DEVICE_AVAILABLE
] = UNIT_ACTIVE
17 static const char* const state_string_table
[_DEVICE_STATE_MAX
] = {
18 [DEVICE_DEAD
] = "dead",
19 [DEVICE_AVAILABLE
] = "available"
22 static void device_done(Unit
*u
) {
23 Device
*d
= DEVICE(u
);
29 static void device_set_state(Device
*d
, DeviceState state
) {
30 DeviceState old_state
;
36 log_debug("%s changed %s → %s", unit_id(UNIT(d
)), state_string_table
[old_state
], state_string_table
[state
]);
38 unit_notify(UNIT(d
), state_translation_table
[old_state
], state_translation_table
[state
]);
41 static int device_coldplug(Unit
*u
) {
42 Device
*d
= DEVICE(u
);
45 assert(d
->state
== DEVICE_DEAD
);
48 device_set_state(d
, DEVICE_AVAILABLE
);
53 static void device_dump(Unit
*u
, FILE *f
, const char *prefix
) {
54 Device
*d
= DEVICE(u
);
59 "%sDevice State: %s\n"
61 prefix
, state_string_table
[d
->state
],
62 prefix
, strna(d
->sysfs
));
65 static UnitActiveState
device_active_state(Unit
*u
) {
68 return state_translation_table
[DEVICE(u
)->state
];
71 static int device_add_escaped_name(Unit
*u
, const char *prefix
, const char *dn
, bool make_id
) {
79 if (!(e
= unit_name_escape_path(prefix
, dn
+1, ".device")))
82 r
= unit_add_name(u
, e
);
84 if (r
>= 0 && make_id
)
89 if (r
< 0 && r
!= -EEXIST
)
95 static int device_process_new_device(Manager
*m
, struct udev_device
*dev
, bool update_state
) {
96 const char *dn
, *names
, *wants
, *sysfs
;
102 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
106 /* Check whether this entry is even relevant for us. */
107 dn
= udev_device_get_devnode(dev
);
108 names
= udev_device_get_property_value(dev
, "SYSTEMD_NAMES");
109 wants
= udev_device_get_property_value(dev
, "SYSTEMD_WANTS");
111 if (!dn
&& !names
&& !wants
)
114 /* Ok, seems kinda interesting. Now, let's see if this one
117 if (!(sysfs
= udev_device_get_syspath(dev
)))
120 assert(sysfs
[0] == '/');
121 if (!(e
= unit_name_escape_path("sysfs-", sysfs
+1, ".device")))
124 if (!(u
= manager_get_unit(m
, e
))) {
129 if (!(u
= unit_new(m
))) {
134 r
= unit_add_name(u
, e
);
140 if (!(DEVICE(u
)->sysfs
= strdup(sysfs
))) {
145 if ((model
= udev_device_get_property_value(dev
, "ID_MODEL_FROM_DATABASE")) ||
146 (model
= udev_device_get_property_value(dev
, "ID_MODEL")))
147 if ((r
= unit_set_description(u
, model
)) < 0)
150 unit_add_to_load_queue(u
);
157 if ((r
= device_add_escaped_name(u
, "node-", dn
, true)) < 0)
160 first
= udev_device_get_devlinks_list_entry(dev
);
161 udev_list_entry_foreach(item
, first
)
162 if ((r
= device_add_escaped_name(u
, "node-", udev_list_entry_get_name(item
), false)) < 0)
166 FOREACH_WORD(w
, l
, names
, state
) {
167 if (!(e
= strndup(w
, l
)))
170 r
= unit_add_name(u
, e
);
173 if (r
< 0 && r
!= -EEXIST
)
179 FOREACH_WORD(w
, l
, wants
, state
) {
180 if (!(e
= strndup(w
, l
)))
183 r
= unit_add_dependency_by_name(u
, UNIT_WANTS
, e
);
192 manager_dispatch_load_queue(u
->meta
.manager
);
193 device_set_state(DEVICE(u
), DEVICE_AVAILABLE
);
204 static int device_process_path(Manager
*m
, const char *path
, bool update_state
) {
206 struct udev_device
*dev
;
211 if (!(dev
= udev_device_new_from_syspath(m
->udev
, path
))) {
212 log_warning("Failed to get udev device object from udev for path %s.", path
);
216 r
= device_process_new_device(m
, dev
, update_state
);
217 udev_device_unref(dev
);
221 static int device_process_removed_device(Manager
*m
, struct udev_device
*dev
) {
230 if (!(sysfs
= udev_device_get_syspath(dev
)))
233 assert(sysfs
[0] == '/');
234 if (!(e
= unit_name_escape_path("sysfs-", sysfs
+1, ".device")))
237 u
= manager_get_unit(m
, e
);
247 device_set_state(d
, DEVICE_DEAD
);
251 static void device_shutdown(Manager
*m
) {
255 udev_monitor_unref(m
->udev_monitor
);
261 static int device_enumerate(Manager
*m
) {
262 struct epoll_event ev
;
264 struct udev_enumerate
*e
= NULL
;
265 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
269 if (!(m
->udev
= udev_new()))
272 if (!(m
->udev_monitor
= udev_monitor_new_from_netlink(m
->udev
, "udev"))) {
277 if (udev_monitor_enable_receiving(m
->udev_monitor
) < 0) {
282 m
->udev_watch
.type
= WATCH_UDEV
;
283 m
->udev_watch
.fd
= udev_monitor_get_fd(m
->udev_monitor
);
287 ev
.data
.ptr
= &m
->udev_watch
;
289 if (epoll_ctl(m
->epoll_fd
, EPOLL_CTL_ADD
, m
->udev_watch
.fd
, &ev
) < 0)
292 if (!(e
= udev_enumerate_new(m
->udev
))) {
297 if (udev_enumerate_scan_devices(e
) < 0) {
302 first
= udev_enumerate_get_list_entry(e
);
303 udev_list_entry_foreach(item
, first
)
304 device_process_path(m
, udev_list_entry_get_name(item
), false);
306 udev_enumerate_unref(e
);
311 udev_enumerate_unref(e
);
317 void device_fd_event(Manager
*m
, int events
) {
318 struct udev_device
*dev
;
323 assert(events
== EPOLLIN
);
325 log_debug("got udev event");
327 if (!(dev
= udev_monitor_receive_device(m
->udev_monitor
))) {
328 log_error("Failed to receive device.");
332 if (!(action
= udev_device_get_action(dev
))) {
333 log_error("Failed to get udev action string.");
337 if (streq(action
, "remove")) {
338 if ((r
= device_process_removed_device(m
, dev
)) < 0) {
339 log_error("Failed to process udev device event: %s", strerror(-r
));
343 if ((r
= device_process_new_device(m
, dev
, true)) < 0) {
344 log_error("Failed to process udev device event: %s", strerror(-r
));
350 udev_device_unref(dev
);
353 const UnitVTable device_vtable
= {
356 .init
= unit_load_fragment_and_dropin
,
358 .coldplug
= device_coldplug
,
362 .active_state
= device_active_state
,
364 .enumerate
= device_enumerate
,
365 .shutdown
= device_shutdown