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