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