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