chiark / gitweb /
8121dc95d1126e861dffa99bc67009bf13b2bbe5
[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
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                 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
273                                         r = device_add_escaped_name(u, e);
274                                         free(e);
275                                         if (r < 0)
276                                                 goto fail;
277                                 }
278                         }
279                 }
280
281                 wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
282                 if (wants) {
283                         char *state, *w;
284                         size_t l;
285
286                         FOREACH_WORD_QUOTED(w, l, wants, state) {
287                                 char *e;
288
289                                 e = strndup(w, l);
290                                 if (!e) {
291                                         r = -ENOMEM;
292                                         goto fail;
293                                 }
294
295                                 r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
296                                 free(e);
297                                 if (r < 0)
298                                         goto fail;
299                         }
300                 }
301         }
302
303         unit_add_to_dbus_queue(u);
304         return 0;
305
306 fail:
307         log_warning("Failed to load device unit: %s", strerror(-r));
308
309         if (delete && u)
310                 unit_free(u);
311
312         return r;
313 }
314
315 static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
316         const char *sysfs, *dn;
317         struct udev_list_entry *item = NULL, *first = NULL;
318
319         assert(m);
320
321         if (!(sysfs = udev_device_get_syspath(dev)))
322                 return -ENOMEM;
323
324         /* Add the main unit named after the sysfs path */
325         device_update_unit(m, dev, sysfs, true);
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         struct epoll_event ev;
484         int r;
485         struct udev_enumerate *e = NULL;
486         struct udev_list_entry *item = NULL, *first = NULL;
487
488         assert(m);
489
490         if (!m->udev) {
491                 if (!(m->udev = udev_new()))
492                         return -ENOMEM;
493
494                 if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
495                         r = -ENOMEM;
496                         goto fail;
497                 }
498
499                 /* This will fail if we are unprivileged, but that
500                  * should not matter much, as user instances won't run
501                  * during boot. */
502                 udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
503
504                 if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
505                         r = -ENOMEM;
506                         goto fail;
507                 }
508
509                 if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
510                         r = -EIO;
511                         goto fail;
512                 }
513
514                 m->udev_watch.type = WATCH_UDEV;
515                 m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
516
517                 zero(ev);
518                 ev.events = EPOLLIN;
519                 ev.data.ptr = &m->udev_watch;
520
521                 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
522                         return -errno;
523         }
524
525         if (!(e = udev_enumerate_new(m->udev))) {
526                 r = -ENOMEM;
527                 goto fail;
528         }
529         if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
530                 r = -EIO;
531                 goto fail;
532         }
533
534         if (udev_enumerate_scan_devices(e) < 0) {
535                 r = -EIO;
536                 goto fail;
537         }
538
539         first = udev_enumerate_get_list_entry(e);
540         udev_list_entry_foreach(item, first)
541                 device_process_path(m, udev_list_entry_get_name(item), false);
542
543         udev_enumerate_unref(e);
544         return 0;
545
546 fail:
547         if (e)
548                 udev_enumerate_unref(e);
549
550         device_shutdown(m);
551         return r;
552 }
553
554 void device_fd_event(Manager *m, int events) {
555         struct udev_device *dev;
556         int r;
557         const char *action, *ready;
558
559         assert(m);
560
561         if (events != EPOLLIN) {
562                 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
563
564                 if (!ratelimit_test(&limit))
565                         log_error("Failed to get udev event: %m");
566                 if (!(events & EPOLLIN))
567                         return;
568         }
569
570         if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
571                 /*
572                  * libudev might filter-out devices which pass the bloom filter,
573                  * so getting NULL here is not necessarily an error
574                  */
575                 return;
576         }
577
578         if (!(action = udev_device_get_action(dev))) {
579                 log_error("Failed to get udev action string.");
580                 goto fail;
581         }
582
583         ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
584
585         if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
586                 if ((r = device_process_removed_device(m, dev)) < 0) {
587                         log_error("Failed to process udev device event: %s", strerror(-r));
588                         goto fail;
589                 }
590         } else {
591                 if ((r = device_process_new_device(m, dev, true)) < 0) {
592                         log_error("Failed to process udev device event: %s", strerror(-r));
593                         goto fail;
594                 }
595         }
596
597 fail:
598         udev_device_unref(dev);
599 }
600
601 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
602         [DEVICE_DEAD] = "dead",
603         [DEVICE_PLUGGED] = "plugged"
604 };
605
606 DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
607
608 const UnitVTable device_vtable = {
609         .object_size = sizeof(Device),
610         .sections =
611                 "Unit\0"
612                 "Device\0"
613                 "Install\0",
614
615         .no_instances = true,
616
617         .init = device_init,
618
619         .load = unit_load_fragment_and_dropin_optional,
620         .done = device_done,
621         .coldplug = device_coldplug,
622
623         .dump = device_dump,
624
625         .active_state = device_active_state,
626         .sub_state_to_string = device_sub_state_to_string,
627
628         .bus_interface = "org.freedesktop.systemd1.Device",
629         .bus_message_handler = bus_device_message_handler,
630         .bus_invalidating_properties =  bus_device_invalidating_properties,
631
632         .following = device_following,
633         .following_set = device_following_set,
634
635         .enumerate = device_enumerate,
636         .shutdown = device_shutdown,
637
638         .status_message_formats = {
639                 .starting_stopping = {
640                         [0] = "Expecting device %s...",
641                 },
642                 .finished_start_job = {
643                         [JOB_DONE]       = "Found device %s.",
644                         [JOB_TIMEOUT]    = "Timed out waiting for device %s.",
645                 },
646         },
647 };