]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/device.c
systemctl: automatically turn paths and unescaped unit names into proper unit names
[thirdparty/systemd.git] / src / core / device.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5cb5a6ff 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
25ac040b 22#include <errno.h>
f94ea366 23#include <sys/epoll.h>
25ac040b
LP
24#include <libudev.h>
25
87f0e418 26#include "unit.h"
5cb5a6ff
LP
27#include "device.h"
28#include "strv.h"
25ac040b 29#include "log.h"
9e2f7c11 30#include "unit-name.h"
4139c1b2 31#include "dbus-device.h"
f6a6225e 32#include "def.h"
9eb977db 33#include "path-util.h"
5cb5a6ff 34
f50e0a01
LP
35static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
36 [DEVICE_DEAD] = UNIT_INACTIVE,
73608ed9 37 [DEVICE_PLUGGED] = UNIT_ACTIVE
f50e0a01
LP
38};
39
8fe914ec
LP
40static void device_unset_sysfs(Device *d) {
41 Device *first;
42
43 assert(d);
44
a7f241db
LP
45 if (!d->sysfs)
46 return;
47
48 /* Remove this unit from the chain of devices which share the
49 * same sysfs path. */
1124fe6f 50 first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
a7f241db 51 LIST_REMOVE(Device, same_sysfs, first, d);
8fe914ec 52
a7f241db 53 if (first)
1124fe6f 54 hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
a7f241db 55 else
1124fe6f 56 hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
a7f241db
LP
57
58 free(d->sysfs);
59 d->sysfs = NULL;
8fe914ec
LP
60}
61
faf919f1
LP
62static void device_init(Unit *u) {
63 Device *d = DEVICE(u);
64
65 assert(d);
1124fe6f 66 assert(UNIT(d)->load_state == UNIT_STUB);
faf919f1 67
8fe914ec
LP
68 /* In contrast to all other unit types we timeout jobs waiting
69 * for devices by default. This is because they otherwise wait
35b8ca3a 70 * indefinitely for plugged in devices, something which cannot
8fe914ec
LP
71 * happen for the other units since their operations time out
72 * anyway. */
1124fe6f 73 UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
c8f4d764 74
1124fe6f
MS
75 UNIT(d)->ignore_on_isolate = true;
76 UNIT(d)->ignore_on_snapshot = true;
faf919f1
LP
77}
78
87f0e418
LP
79static void device_done(Unit *u) {
80 Device *d = DEVICE(u);
034c6ed7
LP
81
82 assert(d);
e537352b 83
8fe914ec 84 device_unset_sysfs(d);
e537352b
LP
85}
86
f50e0a01
LP
87static void device_set_state(Device *d, DeviceState state) {
88 DeviceState old_state;
89 assert(d);
5cb5a6ff 90
f50e0a01
LP
91 old_state = d->state;
92 d->state = state;
5cb5a6ff 93
e537352b 94 if (state != old_state)
40d50879 95 log_debug("%s changed %s -> %s",
1124fe6f 96 UNIT(d)->id,
a16e1123
LP
97 device_state_to_string(old_state),
98 device_state_to_string(state));
f50e0a01 99
e2f3b44c 100 unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
f50e0a01
LP
101}
102
103static 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)
73608ed9 110 device_set_state(d, DEVICE_PLUGGED);
f50e0a01
LP
111
112 return 0;
113}
114
115static void device_dump(Unit *u, FILE *f, const char *prefix) {
25ac040b 116 Device *d = DEVICE(u);
5cb5a6ff 117
25ac040b 118 assert(d);
5cb5a6ff
LP
119
120 fprintf(f,
25ac040b
LP
121 "%sDevice State: %s\n"
122 "%sSysfs Path: %s\n",
a16e1123 123 prefix, device_state_to_string(d->state),
f50e0a01
LP
124 prefix, strna(d->sysfs));
125}
126
127static UnitActiveState device_active_state(Unit *u) {
128 assert(u);
129
130 return state_translation_table[DEVICE(u)->state];
25ac040b
LP
131}
132
10a94420
LP
133static const char *device_sub_state_to_string(Unit *u) {
134 assert(u);
135
a16e1123 136 return device_state_to_string(DEVICE(u)->state);
10a94420
LP
137}
138
8fe914ec 139static int device_add_escaped_name(Unit *u, const char *dn) {
25ac040b
LP
140 char *e;
141 int r;
142
143 assert(u);
144 assert(dn);
145 assert(dn[0] == '/');
146
b0193f1c
LP
147 e = unit_name_from_path(dn, ".device");
148 if (!e)
25ac040b
LP
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
aab14b13
LP
160static 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
b0193f1c
LP
169 e = unit_name_from_path(dn, ".device");
170 if (!e)
aab14b13
LP
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
8fe914ec
LP
184static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
185 const char *sysfs, *model;
25ac040b
LP
186 Unit *u = NULL;
187 int r;
25ac040b 188 bool delete;
25ac040b
LP
189
190 assert(m);
191
7f275a9f
LP
192 if (!(sysfs = udev_device_get_syspath(dev)))
193 return -ENOMEM;
194
8fe914ec 195 if ((r = device_find_escape_name(m, path, &u)) < 0)
aab14b13 196 return r;
25ac040b 197
5845b46b 198 if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
8fe914ec 199 return -EEXIST;
25ac040b 200
aab14b13
LP
201 if (!u) {
202 delete = true;
203
7d17cfbc
MS
204 u = unit_new(m, sizeof(Device));
205 if (!u)
aab14b13 206 return -ENOMEM;
25ac040b 207
7d17cfbc
MS
208 r = device_add_escaped_name(u, path);
209 if (r < 0)
25ac040b
LP
210 goto fail;
211
ee6cb288
LP
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
25ac040b
LP
223 if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
224 r = -ENOMEM;
225 goto fail;
226 }
227
8fe914ec
LP
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 }
25ac040b 233
8fe914ec
LP
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)
25ac040b 238 goto fail;
ee6cb288 239 }
8fe914ec 240
aab14b13
LP
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;
4e85aff4 245 } else
8fe914ec 246 if ((r = unit_set_description(u, path)) < 0)
4e85aff4 247 goto fail;
aab14b13 248
8fe914ec
LP
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;
b866264a 260 }
8fe914ec 261 }
25ac040b 262
8fe914ec
LP
263 if ((wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"))) {
264 char *state, *w;
265 size_t l;
25ac040b 266
8fe914ec
LP
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 }
25ac040b 281 }
a7f241db 282 }
f94ea366 283
c1e1601e 284 unit_add_to_dbus_queue(u);
25ac040b
LP
285 return 0;
286
287fail:
ee5f3479
LP
288 log_warning("Failed to load device unit: %s", strerror(-r));
289
25ac040b
LP
290 if (delete && u)
291 unit_free(u);
ee5f3479 292
25ac040b
LP
293 return r;
294}
295
8fe914ec
LP
296static 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;
5845b46b 316 struct stat st;
8fe914ec
LP
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
5845b46b
LP
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
8fe914ec
LP
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
f94ea366 353static int device_process_path(Manager *m, const char *path, bool update_state) {
25ac040b
LP
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
f94ea366 365 r = device_process_new_device(m, dev, update_state);
25ac040b
LP
366 udev_device_unref(dev);
367 return r;
368}
369
f94ea366
LP
370static int device_process_removed_device(Manager *m, struct udev_device *dev) {
371 const char *sysfs;
f94ea366
LP
372 Device *d;
373
374 assert(m);
375 assert(dev);
376
377 if (!(sysfs = udev_device_get_syspath(dev)))
378 return -ENOMEM;
379
8fe914ec
LP
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 }
f94ea366 385
f94ea366
LP
386 return 0;
387}
388
a7f241db
LP
389static Unit *device_following(Unit *u) {
390 Device *d = DEVICE(u);
391 Device *other, *first = NULL;
392
393 assert(d);
394
ac155bb8 395 if (startswith(u->id, "sys-"))
a7f241db
LP
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)
1124fe6f 400 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
401 return UNIT(other);
402
403 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
1124fe6f 404 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
405 return UNIT(other);
406
407 first = other;
408 }
409
410 return UNIT(first);
411}
412
6210e7fc
LP
413static 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
441fail:
442 set_free(s);
443 return r;
444}
445
25ac040b
LP
446static void device_shutdown(Manager *m) {
447 assert(m);
448
a16e1123 449 if (m->udev_monitor) {
f94ea366 450 udev_monitor_unref(m->udev_monitor);
a16e1123
LP
451 m->udev_monitor = NULL;
452 }
f94ea366 453
a16e1123 454 if (m->udev) {
25ac040b 455 udev_unref(m->udev);
a16e1123
LP
456 m->udev = NULL;
457 }
8fe914ec
LP
458
459 hashmap_free(m->devices_by_sysfs);
460 m->devices_by_sysfs = NULL;
25ac040b
LP
461}
462
463static int device_enumerate(Manager *m) {
f94ea366 464 struct epoll_event ev;
25ac040b
LP
465 int r;
466 struct udev_enumerate *e = NULL;
467 struct udev_list_entry *item = NULL, *first = NULL;
468
469 assert(m);
470
a16e1123
LP
471 if (!m->udev) {
472 if (!(m->udev = udev_new()))
473 return -ENOMEM;
25ac040b 474
a16e1123
LP
475 if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
476 r = -ENOMEM;
477 goto fail;
478 }
f94ea366 479
47ae6e67
LP
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);
99448c1f 484
e1ce2c27
LP
485 if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
486 r = -ENOMEM;
487 goto fail;
488 }
489
a16e1123
LP
490 if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
491 r = -EIO;
492 goto fail;
493 }
f94ea366 494
a16e1123
LP
495 m->udev_watch.type = WATCH_UDEV;
496 m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
f94ea366 497
a16e1123
LP
498 zero(ev);
499 ev.events = EPOLLIN;
500 ev.data.ptr = &m->udev_watch;
f94ea366 501
a16e1123
LP
502 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
503 return -errno;
504 }
f94ea366 505
4f2d528d
LP
506 if (!(e = udev_enumerate_new(m->udev))) {
507 r = -ENOMEM;
508 goto fail;
509 }
e1ce2c27
LP
510 if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
511 r = -EIO;
512 goto fail;
513 }
25ac040b 514
4f2d528d
LP
515 if (udev_enumerate_scan_devices(e) < 0) {
516 r = -EIO;
517 goto fail;
518 }
25ac040b 519
4f2d528d
LP
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);
25ac040b 523
4f2d528d 524 udev_enumerate_unref(e);
25ac040b
LP
525 return 0;
526
527fail:
528 if (e)
529 udev_enumerate_unref(e);
530
531 device_shutdown(m);
532 return r;
5cb5a6ff
LP
533}
534
f94ea366
LP
535void device_fd_event(Manager *m, int events) {
536 struct udev_device *dev;
537 int r;
2958c886 538 const char *action, *ready;
f94ea366
LP
539
540 assert(m);
99448c1f
KS
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");
2e6081f2
KS
547 if (!(events & EPOLLIN))
548 return;
99448c1f 549 }
f94ea366 550
f94ea366 551 if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
99448c1f
KS
552 /*
553 * libudev might filter-out devices which pass the bloom filter,
35b8ca3a 554 * so getting NULL here is not necessarily an error
99448c1f 555 */
f94ea366
LP
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
2958c886
LP
564 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
565
566 if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
f94ea366
LP
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
578fail:
579 udev_device_unref(dev);
580}
581
a16e1123
LP
582static const char* const device_state_table[_DEVICE_STATE_MAX] = {
583 [DEVICE_DEAD] = "dead",
73608ed9 584 [DEVICE_PLUGGED] = "plugged"
a16e1123
LP
585};
586
587DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
588
87f0e418 589const UnitVTable device_vtable = {
5cb5a6ff 590 .suffix = ".device",
7d17cfbc 591 .object_size = sizeof(Device),
f975e971
LP
592 .sections =
593 "Unit\0"
594 "Device\0"
595 "Install\0",
5cb5a6ff 596
9e2f7c11
LP
597 .no_instances = true,
598
faf919f1
LP
599 .init = device_init,
600
e537352b 601 .load = unit_load_fragment_and_dropin_optional,
034c6ed7 602 .done = device_done,
f50e0a01
LP
603 .coldplug = device_coldplug,
604
5cb5a6ff
LP
605 .dump = device_dump,
606
f50e0a01 607 .active_state = device_active_state,
10a94420 608 .sub_state_to_string = device_sub_state_to_string,
25ac040b 609
c4e2ceae 610 .bus_interface = "org.freedesktop.systemd1.Device",
4139c1b2 611 .bus_message_handler = bus_device_message_handler,
c4e2ceae 612 .bus_invalidating_properties = bus_device_invalidating_properties,
4139c1b2 613
a7f241db 614 .following = device_following,
6210e7fc 615 .following_set = device_following_set,
a7f241db 616
f50e0a01 617 .enumerate = device_enumerate,
c6918296
MS
618 .shutdown = device_shutdown,
619
620 .status_message_formats = {
621 .starting_stopping = {
622 [0] = "Expecting device %s...",
623 },
624 .finished_start_job = {
625 [JOB_DONE] = "Found device %s.",
626 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
627 },
628 },
5cb5a6ff 629};