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