]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/device.c
Modernization
[thirdparty/systemd.git] / src / core / device.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <sys/epoll.h>
24 #include <libudev.h>
25
26 #include "unit.h"
27 #include "device.h"
28 #include "strv.h"
29 #include "log.h"
30 #include "unit-name.h"
31 #include "dbus-device.h"
32 #include "def.h"
33 #include "path-util.h"
34
35 static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
36 [DEVICE_DEAD] = UNIT_INACTIVE,
37 [DEVICE_PLUGGED] = UNIT_ACTIVE
38 };
39
40 static void device_unset_sysfs(Device *d) {
41 Device *first;
42
43 assert(d);
44
45 if (!d->sysfs)
46 return;
47
48 /* Remove this unit from the chain of devices which share the
49 * same sysfs path. */
50 first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
51 LIST_REMOVE(Device, same_sysfs, first, d);
52
53 if (first)
54 hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
55 else
56 hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
57
58 free(d->sysfs);
59 d->sysfs = NULL;
60 }
61
62 static void device_init(Unit *u) {
63 Device *d = DEVICE(u);
64
65 assert(d);
66 assert(UNIT(d)->load_state == UNIT_STUB);
67
68 /* In contrast to all other unit types we timeout jobs waiting
69 * for devices by default. This is because they otherwise wait
70 * indefinitely for plugged in devices, something which cannot
71 * happen for the other units since their operations time out
72 * anyway. */
73 UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
74
75 UNIT(d)->ignore_on_isolate = true;
76 UNIT(d)->ignore_on_snapshot = true;
77 }
78
79 static void device_done(Unit *u) {
80 Device *d = DEVICE(u);
81
82 assert(d);
83
84 device_unset_sysfs(d);
85 }
86
87 static void device_set_state(Device *d, DeviceState state) {
88 DeviceState old_state;
89 assert(d);
90
91 old_state = d->state;
92 d->state = state;
93
94 if (state != old_state)
95 log_debug_unit(UNIT(d)->id,
96 "%s changed %s -> %s", UNIT(d)->id,
97 device_state_to_string(old_state),
98 device_state_to_string(state));
99
100 unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
101 }
102
103 static int device_coldplug(Unit *u) {
104 Device *d = DEVICE(u);
105
106 assert(d);
107 assert(d->state == DEVICE_DEAD);
108
109 if (d->sysfs)
110 device_set_state(d, DEVICE_PLUGGED);
111
112 return 0;
113 }
114
115 static void device_dump(Unit *u, FILE *f, const char *prefix) {
116 Device *d = DEVICE(u);
117
118 assert(d);
119
120 fprintf(f,
121 "%sDevice State: %s\n"
122 "%sSysfs Path: %s\n",
123 prefix, device_state_to_string(d->state),
124 prefix, strna(d->sysfs));
125 }
126
127 _pure_ static UnitActiveState device_active_state(Unit *u) {
128 assert(u);
129
130 return state_translation_table[DEVICE(u)->state];
131 }
132
133 _pure_ static const char *device_sub_state_to_string(Unit *u) {
134 assert(u);
135
136 return device_state_to_string(DEVICE(u)->state);
137 }
138
139 static int device_add_escaped_name(Unit *u, const char *dn) {
140 char *e;
141 int r;
142
143 assert(u);
144 assert(dn);
145 assert(dn[0] == '/');
146
147 e = unit_name_from_path(dn, ".device");
148 if (!e)
149 return -ENOMEM;
150
151 r = unit_add_name(u, e);
152 free(e);
153
154 if (r < 0 && r != -EEXIST)
155 return r;
156
157 return 0;
158 }
159
160 static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
161 char *e;
162 Unit *u;
163
164 assert(m);
165 assert(dn);
166 assert(dn[0] == '/');
167 assert(_u);
168
169 e = unit_name_from_path(dn, ".device");
170 if (!e)
171 return -ENOMEM;
172
173 u = manager_get_unit(m, e);
174 free(e);
175
176 if (u) {
177 *_u = u;
178 return 1;
179 }
180
181 return 0;
182 }
183
184 static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
185 const char *sysfs, *model;
186 Unit *u = NULL;
187 int r;
188 bool delete;
189
190 assert(m);
191
192 sysfs = udev_device_get_syspath(dev);
193 if (!sysfs)
194 return -ENOMEM;
195
196 r = device_find_escape_name(m, path, &u);
197 if (r < 0)
198 return r;
199
200 if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
201 return -EEXIST;
202
203 if (!u) {
204 delete = true;
205
206 u = unit_new(m, sizeof(Device));
207 if (!u)
208 return -ENOMEM;
209
210 r = device_add_escaped_name(u, path);
211 if (r < 0)
212 goto fail;
213
214 unit_add_to_load_queue(u);
215 } else
216 delete = false;
217
218 /* If this was created via some dependency and has not
219 * actually been seen yet ->sysfs will not be
220 * initialized. Hence initialize it if necessary. */
221
222 if (!DEVICE(u)->sysfs) {
223 Device *first;
224
225 if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
226 r = -ENOMEM;
227 goto fail;
228 }
229
230 if (!m->devices_by_sysfs)
231 if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
232 r = -ENOMEM;
233 goto fail;
234 }
235
236 first = hashmap_get(m->devices_by_sysfs, sysfs);
237 LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
238
239 r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
240 if (r < 0)
241 goto fail;
242 }
243
244 if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
245 (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
246 r = unit_set_description(u, model);
247 if (r < 0)
248 goto fail;
249 } else {
250 r = unit_set_description(u, path);
251 if (r < 0)
252 goto fail;
253 }
254
255 if (main) {
256 /* The additional systemd udev properties we only
257 * interpret for the main object */
258 const char *wants, *alias;
259
260 alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
261 if (alias) {
262 char *state, *w;
263 size_t l;
264
265 FOREACH_WORD_QUOTED(w, l, alias, state) {
266 _cleanup_free_ char *e;
267
268 e = strndup(w, l);
269 if (!e) {
270 r = -ENOMEM;
271 goto fail;
272 }
273
274 if (is_path(e))
275 device_update_unit(m, dev, e, false);
276 else
277 log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
278 }
279 }
280
281 wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
282 if (wants) {
283 char *state, *w;
284 size_t l;
285
286 FOREACH_WORD_QUOTED(w, l, wants, state) {
287 _cleanup_free_ char *e, *n = NULL;
288
289 e = strndup(w, l);
290 if (!e) {
291 r = -ENOMEM;
292 goto fail;
293 }
294
295 n = unit_name_mangle(e);
296 if (!n) {
297 r = -ENOMEM;
298 goto fail;
299 }
300
301 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
302 if (r < 0)
303 goto fail;
304 }
305 }
306 }
307
308 unit_add_to_dbus_queue(u);
309 return 0;
310
311 fail:
312 log_warning("Failed to load device unit: %s", strerror(-r));
313
314 if (delete && u)
315 unit_free(u);
316
317 return r;
318 }
319
320 static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
321 const char *sysfs, *dn;
322 struct udev_list_entry *item = NULL, *first = NULL;
323 int r;
324
325 assert(m);
326
327 if (!(sysfs = udev_device_get_syspath(dev)))
328 return -ENOMEM;
329
330 /* Add the main unit named after the sysfs path */
331 r = device_update_unit(m, dev, sysfs, true);
332 if (r < 0)
333 return r;
334
335 /* Add an additional unit for the device node */
336 if ((dn = udev_device_get_devnode(dev)))
337 device_update_unit(m, dev, dn, false);
338
339 /* Add additional units for all symlinks */
340 first = udev_device_get_devlinks_list_entry(dev);
341 udev_list_entry_foreach(item, first) {
342 const char *p;
343 struct stat st;
344
345 /* Don't bother with the /dev/block links */
346 p = udev_list_entry_get_name(item);
347
348 if (path_startswith(p, "/dev/block/") ||
349 path_startswith(p, "/dev/char/"))
350 continue;
351
352 /* Verify that the symlink in the FS actually belongs
353 * to this device. This is useful to deal with
354 * conflicting devices, e.g. when two disks want the
355 * same /dev/disk/by-label/xxx link because they have
356 * the same label. We want to make sure that the same
357 * device that won the symlink wins in systemd, so we
358 * check the device node major/minor*/
359 if (stat(p, &st) >= 0)
360 if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
361 st.st_rdev != udev_device_get_devnum(dev))
362 continue;
363
364 device_update_unit(m, dev, p, false);
365 }
366
367 if (update_state) {
368 Device *d, *l;
369
370 manager_dispatch_load_queue(m);
371
372 l = hashmap_get(m->devices_by_sysfs, sysfs);
373 LIST_FOREACH(same_sysfs, d, l)
374 device_set_state(d, DEVICE_PLUGGED);
375 }
376
377 return 0;
378 }
379
380 static int device_process_path(Manager *m, const char *path, bool update_state) {
381 int r;
382 struct udev_device *dev;
383
384 assert(m);
385 assert(path);
386
387 if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
388 log_warning("Failed to get udev device object from udev for path %s.", path);
389 return -ENOMEM;
390 }
391
392 r = device_process_new_device(m, dev, update_state);
393 udev_device_unref(dev);
394 return r;
395 }
396
397 static int device_process_removed_device(Manager *m, struct udev_device *dev) {
398 const char *sysfs;
399 Device *d;
400
401 assert(m);
402 assert(dev);
403
404 if (!(sysfs = udev_device_get_syspath(dev)))
405 return -ENOMEM;
406
407 /* Remove all units of this sysfs path */
408 while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
409 device_unset_sysfs(d);
410 device_set_state(d, DEVICE_DEAD);
411 }
412
413 return 0;
414 }
415
416 static Unit *device_following(Unit *u) {
417 Device *d = DEVICE(u);
418 Device *other, *first = NULL;
419
420 assert(d);
421
422 if (startswith(u->id, "sys-"))
423 return NULL;
424
425 /* Make everybody follow the unit that's named after the sysfs path */
426 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
427 if (startswith(UNIT(other)->id, "sys-"))
428 return UNIT(other);
429
430 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
431 if (startswith(UNIT(other)->id, "sys-"))
432 return UNIT(other);
433
434 first = other;
435 }
436
437 return UNIT(first);
438 }
439
440 static int device_following_set(Unit *u, Set **_s) {
441 Device *d = DEVICE(u);
442 Device *other;
443 Set *s;
444 int r;
445
446 assert(d);
447 assert(_s);
448
449 if (!d->same_sysfs_prev && !d->same_sysfs_next) {
450 *_s = NULL;
451 return 0;
452 }
453
454 if (!(s = set_new(NULL, NULL)))
455 return -ENOMEM;
456
457 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
458 if ((r = set_put(s, other)) < 0)
459 goto fail;
460
461 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
462 if ((r = set_put(s, other)) < 0)
463 goto fail;
464
465 *_s = s;
466 return 1;
467
468 fail:
469 set_free(s);
470 return r;
471 }
472
473 static void device_shutdown(Manager *m) {
474 assert(m);
475
476 if (m->udev_monitor) {
477 udev_monitor_unref(m->udev_monitor);
478 m->udev_monitor = NULL;
479 }
480
481 if (m->udev) {
482 udev_unref(m->udev);
483 m->udev = NULL;
484 }
485
486 hashmap_free(m->devices_by_sysfs);
487 m->devices_by_sysfs = NULL;
488 }
489
490 static int device_enumerate(Manager *m) {
491 int r;
492 struct udev_enumerate *e = NULL;
493 struct udev_list_entry *item = NULL, *first = NULL;
494
495 assert(m);
496
497 if (!m->udev) {
498 struct epoll_event ev;
499
500 if (!(m->udev = udev_new()))
501 return -ENOMEM;
502
503 if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
504 r = -ENOMEM;
505 goto fail;
506 }
507
508 /* This will fail if we are unprivileged, but that
509 * should not matter much, as user instances won't run
510 * during boot. */
511 udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
512
513 if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
514 r = -ENOMEM;
515 goto fail;
516 }
517
518 if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
519 r = -EIO;
520 goto fail;
521 }
522
523 m->udev_watch.type = WATCH_UDEV;
524 m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
525
526 zero(ev);
527 ev.events = EPOLLIN;
528 ev.data.ptr = &m->udev_watch;
529
530 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
531 return -errno;
532 }
533
534 if (!(e = udev_enumerate_new(m->udev))) {
535 r = -ENOMEM;
536 goto fail;
537 }
538 if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
539 r = -EIO;
540 goto fail;
541 }
542
543 if (udev_enumerate_scan_devices(e) < 0) {
544 r = -EIO;
545 goto fail;
546 }
547
548 first = udev_enumerate_get_list_entry(e);
549 udev_list_entry_foreach(item, first)
550 device_process_path(m, udev_list_entry_get_name(item), false);
551
552 udev_enumerate_unref(e);
553 return 0;
554
555 fail:
556 if (e)
557 udev_enumerate_unref(e);
558
559 device_shutdown(m);
560 return r;
561 }
562
563 void device_fd_event(Manager *m, int events) {
564 struct udev_device *dev;
565 int r;
566 const char *action, *ready;
567
568 assert(m);
569
570 if (events != EPOLLIN) {
571 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
572
573 if (!ratelimit_test(&limit))
574 log_error("Failed to get udev event: %m");
575 if (!(events & EPOLLIN))
576 return;
577 }
578
579 if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
580 /*
581 * libudev might filter-out devices which pass the bloom filter,
582 * so getting NULL here is not necessarily an error
583 */
584 return;
585 }
586
587 if (!(action = udev_device_get_action(dev))) {
588 log_error("Failed to get udev action string.");
589 goto fail;
590 }
591
592 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
593
594 if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
595 if ((r = device_process_removed_device(m, dev)) < 0) {
596 log_error("Failed to process udev device event: %s", strerror(-r));
597 goto fail;
598 }
599 } else {
600 if ((r = device_process_new_device(m, dev, true)) < 0) {
601 log_error("Failed to process udev device event: %s", strerror(-r));
602 goto fail;
603 }
604 }
605
606 fail:
607 udev_device_unref(dev);
608 }
609
610 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
611 [DEVICE_DEAD] = "dead",
612 [DEVICE_PLUGGED] = "plugged"
613 };
614
615 DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
616
617 const UnitVTable device_vtable = {
618 .object_size = sizeof(Device),
619 .sections =
620 "Unit\0"
621 "Device\0"
622 "Install\0",
623
624 .no_instances = true,
625
626 .init = device_init,
627
628 .load = unit_load_fragment_and_dropin_optional,
629 .done = device_done,
630 .coldplug = device_coldplug,
631
632 .dump = device_dump,
633
634 .active_state = device_active_state,
635 .sub_state_to_string = device_sub_state_to_string,
636
637 .bus_interface = "org.freedesktop.systemd1.Device",
638 .bus_message_handler = bus_device_message_handler,
639 .bus_invalidating_properties = bus_device_invalidating_properties,
640
641 .following = device_following,
642 .following_set = device_following_set,
643
644 .enumerate = device_enumerate,
645 .shutdown = device_shutdown,
646
647 .status_message_formats = {
648 .starting_stopping = {
649 [0] = "Expecting device %s...",
650 },
651 .finished_start_job = {
652 [JOB_DONE] = "Found device %s.",
653 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
654 },
655 },
656 };