]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/device.c
unit: get rid of UnitVTable.suffix, which is now unused
[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("%s changed %s -> %s",
96 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 static UnitActiveState device_active_state(Unit *u) {
128 assert(u);
129
130 return state_translation_table[DEVICE(u)->state];
131 }
132
133 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 if (!(sysfs = udev_device_get_syspath(dev)))
193 return -ENOMEM;
194
195 if ((r = device_find_escape_name(m, path, &u)) < 0)
196 return r;
197
198 if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
199 return -EEXIST;
200
201 if (!u) {
202 delete = true;
203
204 u = unit_new(m, sizeof(Device));
205 if (!u)
206 return -ENOMEM;
207
208 r = device_add_escaped_name(u, path);
209 if (r < 0)
210 goto fail;
211
212 unit_add_to_load_queue(u);
213 } else
214 delete = false;
215
216 /* If this was created via some dependency and has not
217 * actually been seen yet ->sysfs will not be
218 * initialized. Hence initialize it if necessary. */
219
220 if (!DEVICE(u)->sysfs) {
221 Device *first;
222
223 if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
224 r = -ENOMEM;
225 goto fail;
226 }
227
228 if (!m->devices_by_sysfs)
229 if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
230 r = -ENOMEM;
231 goto fail;
232 }
233
234 first = hashmap_get(m->devices_by_sysfs, sysfs);
235 LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
236
237 if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 0)
238 goto fail;
239 }
240
241 if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
242 (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
243 if ((r = unit_set_description(u, model)) < 0)
244 goto fail;
245 } else
246 if ((r = unit_set_description(u, path)) < 0)
247 goto fail;
248
249 if (main) {
250 /* The additional systemd udev properties we only
251 * interpret for the main object */
252 const char *wants, *alias;
253
254 if ((alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS"))) {
255 if (!is_path(alias))
256 log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias);
257 else {
258 if ((r = device_add_escaped_name(u, alias)) < 0)
259 goto fail;
260 }
261 }
262
263 if ((wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"))) {
264 char *state, *w;
265 size_t l;
266
267 FOREACH_WORD_QUOTED(w, l, wants, state) {
268 char *e;
269
270 if (!(e = strndup(w, l))) {
271 r = -ENOMEM;
272 goto fail;
273 }
274
275 r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
276 free(e);
277
278 if (r < 0)
279 goto fail;
280 }
281 }
282 }
283
284 unit_add_to_dbus_queue(u);
285 return 0;
286
287 fail:
288 log_warning("Failed to load device unit: %s", strerror(-r));
289
290 if (delete && u)
291 unit_free(u);
292
293 return r;
294 }
295
296 static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
297 const char *sysfs, *dn;
298 struct udev_list_entry *item = NULL, *first = NULL;
299
300 assert(m);
301
302 if (!(sysfs = udev_device_get_syspath(dev)))
303 return -ENOMEM;
304
305 /* Add the main unit named after the sysfs path */
306 device_update_unit(m, dev, sysfs, true);
307
308 /* Add an additional unit for the device node */
309 if ((dn = udev_device_get_devnode(dev)))
310 device_update_unit(m, dev, dn, false);
311
312 /* Add additional units for all symlinks */
313 first = udev_device_get_devlinks_list_entry(dev);
314 udev_list_entry_foreach(item, first) {
315 const char *p;
316 struct stat st;
317
318 /* Don't bother with the /dev/block links */
319 p = udev_list_entry_get_name(item);
320
321 if (path_startswith(p, "/dev/block/") ||
322 path_startswith(p, "/dev/char/"))
323 continue;
324
325 /* Verify that the symlink in the FS actually belongs
326 * to this device. This is useful to deal with
327 * conflicting devices, e.g. when two disks want the
328 * same /dev/disk/by-label/xxx link because they have
329 * the same label. We want to make sure that the same
330 * device that won the symlink wins in systemd, so we
331 * check the device node major/minor*/
332 if (stat(p, &st) >= 0)
333 if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
334 st.st_rdev != udev_device_get_devnum(dev))
335 continue;
336
337 device_update_unit(m, dev, p, false);
338 }
339
340 if (update_state) {
341 Device *d, *l;
342
343 manager_dispatch_load_queue(m);
344
345 l = hashmap_get(m->devices_by_sysfs, sysfs);
346 LIST_FOREACH(same_sysfs, d, l)
347 device_set_state(d, DEVICE_PLUGGED);
348 }
349
350 return 0;
351 }
352
353 static int device_process_path(Manager *m, const char *path, bool update_state) {
354 int r;
355 struct udev_device *dev;
356
357 assert(m);
358 assert(path);
359
360 if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
361 log_warning("Failed to get udev device object from udev for path %s.", path);
362 return -ENOMEM;
363 }
364
365 r = device_process_new_device(m, dev, update_state);
366 udev_device_unref(dev);
367 return r;
368 }
369
370 static int device_process_removed_device(Manager *m, struct udev_device *dev) {
371 const char *sysfs;
372 Device *d;
373
374 assert(m);
375 assert(dev);
376
377 if (!(sysfs = udev_device_get_syspath(dev)))
378 return -ENOMEM;
379
380 /* Remove all units of this sysfs path */
381 while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
382 device_unset_sysfs(d);
383 device_set_state(d, DEVICE_DEAD);
384 }
385
386 return 0;
387 }
388
389 static Unit *device_following(Unit *u) {
390 Device *d = DEVICE(u);
391 Device *other, *first = NULL;
392
393 assert(d);
394
395 if (startswith(u->id, "sys-"))
396 return NULL;
397
398 /* Make everybody follow the unit that's named after the sysfs path */
399 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
400 if (startswith(UNIT(other)->id, "sys-"))
401 return UNIT(other);
402
403 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
404 if (startswith(UNIT(other)->id, "sys-"))
405 return UNIT(other);
406
407 first = other;
408 }
409
410 return UNIT(first);
411 }
412
413 static int device_following_set(Unit *u, Set **_s) {
414 Device *d = DEVICE(u);
415 Device *other;
416 Set *s;
417 int r;
418
419 assert(d);
420 assert(_s);
421
422 if (!d->same_sysfs_prev && !d->same_sysfs_next) {
423 *_s = NULL;
424 return 0;
425 }
426
427 if (!(s = set_new(NULL, NULL)))
428 return -ENOMEM;
429
430 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
431 if ((r = set_put(s, other)) < 0)
432 goto fail;
433
434 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
435 if ((r = set_put(s, other)) < 0)
436 goto fail;
437
438 *_s = s;
439 return 1;
440
441 fail:
442 set_free(s);
443 return r;
444 }
445
446 static void device_shutdown(Manager *m) {
447 assert(m);
448
449 if (m->udev_monitor) {
450 udev_monitor_unref(m->udev_monitor);
451 m->udev_monitor = NULL;
452 }
453
454 if (m->udev) {
455 udev_unref(m->udev);
456 m->udev = NULL;
457 }
458
459 hashmap_free(m->devices_by_sysfs);
460 m->devices_by_sysfs = NULL;
461 }
462
463 static int device_enumerate(Manager *m) {
464 struct epoll_event ev;
465 int r;
466 struct udev_enumerate *e = NULL;
467 struct udev_list_entry *item = NULL, *first = NULL;
468
469 assert(m);
470
471 if (!m->udev) {
472 if (!(m->udev = udev_new()))
473 return -ENOMEM;
474
475 if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
476 r = -ENOMEM;
477 goto fail;
478 }
479
480 /* This will fail if we are unprivileged, but that
481 * should not matter much, as user instances won't run
482 * during boot. */
483 udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
484
485 if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
486 r = -ENOMEM;
487 goto fail;
488 }
489
490 if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
491 r = -EIO;
492 goto fail;
493 }
494
495 m->udev_watch.type = WATCH_UDEV;
496 m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
497
498 zero(ev);
499 ev.events = EPOLLIN;
500 ev.data.ptr = &m->udev_watch;
501
502 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
503 return -errno;
504 }
505
506 if (!(e = udev_enumerate_new(m->udev))) {
507 r = -ENOMEM;
508 goto fail;
509 }
510 if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
511 r = -EIO;
512 goto fail;
513 }
514
515 if (udev_enumerate_scan_devices(e) < 0) {
516 r = -EIO;
517 goto fail;
518 }
519
520 first = udev_enumerate_get_list_entry(e);
521 udev_list_entry_foreach(item, first)
522 device_process_path(m, udev_list_entry_get_name(item), false);
523
524 udev_enumerate_unref(e);
525 return 0;
526
527 fail:
528 if (e)
529 udev_enumerate_unref(e);
530
531 device_shutdown(m);
532 return r;
533 }
534
535 void device_fd_event(Manager *m, int events) {
536 struct udev_device *dev;
537 int r;
538 const char *action, *ready;
539
540 assert(m);
541
542 if (events != EPOLLIN) {
543 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
544
545 if (!ratelimit_test(&limit))
546 log_error("Failed to get udev event: %m");
547 if (!(events & EPOLLIN))
548 return;
549 }
550
551 if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
552 /*
553 * libudev might filter-out devices which pass the bloom filter,
554 * so getting NULL here is not necessarily an error
555 */
556 return;
557 }
558
559 if (!(action = udev_device_get_action(dev))) {
560 log_error("Failed to get udev action string.");
561 goto fail;
562 }
563
564 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
565
566 if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
567 if ((r = device_process_removed_device(m, dev)) < 0) {
568 log_error("Failed to process udev device event: %s", strerror(-r));
569 goto fail;
570 }
571 } else {
572 if ((r = device_process_new_device(m, dev, true)) < 0) {
573 log_error("Failed to process udev device event: %s", strerror(-r));
574 goto fail;
575 }
576 }
577
578 fail:
579 udev_device_unref(dev);
580 }
581
582 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
583 [DEVICE_DEAD] = "dead",
584 [DEVICE_PLUGGED] = "plugged"
585 };
586
587 DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
588
589 const UnitVTable device_vtable = {
590 .object_size = sizeof(Device),
591 .sections =
592 "Unit\0"
593 "Device\0"
594 "Install\0",
595
596 .no_instances = true,
597
598 .init = device_init,
599
600 .load = unit_load_fragment_and_dropin_optional,
601 .done = device_done,
602 .coldplug = device_coldplug,
603
604 .dump = device_dump,
605
606 .active_state = device_active_state,
607 .sub_state_to_string = device_sub_state_to_string,
608
609 .bus_interface = "org.freedesktop.systemd1.Device",
610 .bus_message_handler = bus_device_message_handler,
611 .bus_invalidating_properties = bus_device_invalidating_properties,
612
613 .following = device_following,
614 .following_set = device_following_set,
615
616 .enumerate = device_enumerate,
617 .shutdown = device_shutdown,
618
619 .status_message_formats = {
620 .starting_stopping = {
621 [0] = "Expecting device %s...",
622 },
623 .finished_start_job = {
624 [JOB_DONE] = "Found device %s.",
625 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
626 },
627 },
628 };