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