chiark / gitweb /
install: use const where we can
[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(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 = u->manager->default_timeout_start_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_unit(UNIT(d)->id,
96                                "%s changed %s -> %s", 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 _pure_ static UnitActiveState device_active_state(Unit *u) {
128         assert(u);
129
130         return state_translation_table[DEVICE(u)->state];
131 }
132
133 _pure_ 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         sysfs = udev_device_get_syspath(dev);
193         if (!sysfs)
194                 return -ENOMEM;
195
196         r = device_find_escape_name(m, path, &u);
197         if (r < 0)
198                 return r;
199
200         if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
201                 return -EEXIST;
202
203         if (!u) {
204                 delete = true;
205
206                 u = unit_new(m, sizeof(Device));
207                 if (!u)
208                         return -ENOMEM;
209
210                 r = device_add_escaped_name(u, path);
211                 if (r < 0)
212                         goto fail;
213
214                 unit_add_to_load_queue(u);
215         } else
216                 delete = false;
217
218         /* If this was created via some dependency and has not
219          * actually been seen yet ->sysfs will not be
220          * initialized. Hence initialize it if necessary. */
221
222         if (!DEVICE(u)->sysfs) {
223                 Device *first;
224
225                 if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
226                         r = -ENOMEM;
227                         goto fail;
228                 }
229
230                 if (!m->devices_by_sysfs)
231                         if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
232                                 r = -ENOMEM;
233                                 goto fail;
234                         }
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                 if (r < 0)
248                         goto fail;
249         } else {
250                 r = unit_set_description(u, path);
251                 if (r < 0)
252                         goto fail;
253         }
254
255         if (main) {
256                 /* The additional systemd udev properties we only
257                  * interpret for the main object */
258                 const char *wants, *alias;
259
260                 alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
261                 if (alias) {
262                         char *state, *w;
263                         size_t l;
264
265                         FOREACH_WORD_QUOTED(w, l, alias, state) {
266                                 _cleanup_free_ char *e;
267
268                                 e = strndup(w, l);
269                                 if (!e) {
270                                         r = -ENOMEM;
271                                         goto fail;
272                                 }
273
274                                 if (is_path(e))
275                                         device_update_unit(m, dev, e, false);
276                                 else
277                                         log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
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                                 _cleanup_free_ char *e, *n = NULL;
288
289                                 e = strndup(w, l);
290                                 if (!e) {
291                                         r = -ENOMEM;
292                                         goto fail;
293                                 }
294
295                                 n = unit_name_mangle(e);
296                                 if (!n) {
297                                         r = -ENOMEM;
298                                         goto fail;
299                                 }
300
301                                 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
302                                 if (r < 0)
303                                         goto fail;
304                         }
305                 }
306         }
307
308         unit_add_to_dbus_queue(u);
309         return 0;
310
311 fail:
312         log_warning("Failed to load device unit: %s", strerror(-r));
313
314         if (delete && u)
315                 unit_free(u);
316
317         return r;
318 }
319
320 static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
321         const char *sysfs, *dn;
322         struct udev_list_entry *item = NULL, *first = NULL;
323         int r;
324
325         assert(m);
326
327         if (!(sysfs = udev_device_get_syspath(dev)))
328                 return -ENOMEM;
329
330         /* Add the main unit named after the sysfs path */
331         r = device_update_unit(m, dev, sysfs, true);
332         if (r < 0)
333                 return r;
334
335         /* Add an additional unit for the device node */
336         if ((dn = udev_device_get_devnode(dev)))
337                 device_update_unit(m, dev, dn, false);
338
339         /* Add additional units for all symlinks */
340         first = udev_device_get_devlinks_list_entry(dev);
341         udev_list_entry_foreach(item, first) {
342                 const char *p;
343                 struct stat st;
344
345                 /* Don't bother with the /dev/block links */
346                 p = udev_list_entry_get_name(item);
347
348                 if (path_startswith(p, "/dev/block/") ||
349                     path_startswith(p, "/dev/char/"))
350                         continue;
351
352                 /* Verify that the symlink in the FS actually belongs
353                  * to this device. This is useful to deal with
354                  * conflicting devices, e.g. when two disks want the
355                  * same /dev/disk/by-label/xxx link because they have
356                  * the same label. We want to make sure that the same
357                  * device that won the symlink wins in systemd, so we
358                  * check the device node major/minor*/
359                 if (stat(p, &st) >= 0)
360                         if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
361                             st.st_rdev != udev_device_get_devnum(dev))
362                                 continue;
363
364                 device_update_unit(m, dev, p, false);
365         }
366
367         if (update_state) {
368                 Device *d, *l;
369
370                 manager_dispatch_load_queue(m);
371
372                 l = hashmap_get(m->devices_by_sysfs, sysfs);
373                 LIST_FOREACH(same_sysfs, d, l)
374                         device_set_state(d, DEVICE_PLUGGED);
375         }
376
377         return 0;
378 }
379
380 static int device_process_path(Manager *m, const char *path, bool update_state) {
381         int r;
382         struct udev_device *dev;
383
384         assert(m);
385         assert(path);
386
387         if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
388                 log_warning("Failed to get udev device object from udev for path %s.", path);
389                 return -ENOMEM;
390         }
391
392         r = device_process_new_device(m, dev, update_state);
393         udev_device_unref(dev);
394         return r;
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         if (!(sysfs = udev_device_get_syspath(dev)))
405                 return -ENOMEM;
406
407         /* Remove all units of this sysfs path */
408         while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
409                 device_unset_sysfs(d);
410                 device_set_state(d, DEVICE_DEAD);
411         }
412
413         return 0;
414 }
415
416 static Unit *device_following(Unit *u) {
417         Device *d = DEVICE(u);
418         Device *other, *first = NULL;
419
420         assert(d);
421
422         if (startswith(u->id, "sys-"))
423                 return NULL;
424
425         /* Make everybody follow the unit that's named after the sysfs path */
426         for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
427                 if (startswith(UNIT(other)->id, "sys-"))
428                         return UNIT(other);
429
430         for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
431                 if (startswith(UNIT(other)->id, "sys-"))
432                         return UNIT(other);
433
434                 first = other;
435         }
436
437         return UNIT(first);
438 }
439
440 static int device_following_set(Unit *u, Set **_s) {
441         Device *d = DEVICE(u);
442         Device *other;
443         Set *s;
444         int r;
445
446         assert(d);
447         assert(_s);
448
449         if (!d->same_sysfs_prev && !d->same_sysfs_next) {
450                 *_s = NULL;
451                 return 0;
452         }
453
454         if (!(s = set_new(NULL, NULL)))
455                 return -ENOMEM;
456
457         for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
458                 if ((r = set_put(s, other)) < 0)
459                         goto fail;
460
461         for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
462                 if ((r = set_put(s, other)) < 0)
463                         goto fail;
464
465         *_s = s;
466         return 1;
467
468 fail:
469         set_free(s);
470         return r;
471 }
472
473 static void device_shutdown(Manager *m) {
474         assert(m);
475
476         if (m->udev_monitor) {
477                 udev_monitor_unref(m->udev_monitor);
478                 m->udev_monitor = NULL;
479         }
480
481         if (m->udev) {
482                 udev_unref(m->udev);
483                 m->udev = NULL;
484         }
485
486         hashmap_free(m->devices_by_sysfs);
487         m->devices_by_sysfs = NULL;
488 }
489
490 static int device_enumerate(Manager *m) {
491         int r;
492         struct udev_enumerate *e = NULL;
493         struct udev_list_entry *item = NULL, *first = NULL;
494
495         assert(m);
496
497         if (!m->udev) {
498                 struct epoll_event ev;
499
500                 if (!(m->udev = udev_new()))
501                         return -ENOMEM;
502
503                 if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
504                         r = -ENOMEM;
505                         goto fail;
506                 }
507
508                 /* This will fail if we are unprivileged, but that
509                  * should not matter much, as user instances won't run
510                  * during boot. */
511                 udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
512
513                 if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
514                         r = -ENOMEM;
515                         goto fail;
516                 }
517
518                 if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
519                         r = -EIO;
520                         goto fail;
521                 }
522
523                 m->udev_watch.type = WATCH_UDEV;
524                 m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
525
526                 zero(ev);
527                 ev.events = EPOLLIN;
528                 ev.data.ptr = &m->udev_watch;
529
530                 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
531                         return -errno;
532         }
533
534         if (!(e = udev_enumerate_new(m->udev))) {
535                 r = -ENOMEM;
536                 goto fail;
537         }
538         if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
539                 r = -EIO;
540                 goto fail;
541         }
542
543         if (udev_enumerate_scan_devices(e) < 0) {
544                 r = -EIO;
545                 goto fail;
546         }
547
548         first = udev_enumerate_get_list_entry(e);
549         udev_list_entry_foreach(item, first)
550                 device_process_path(m, udev_list_entry_get_name(item), false);
551
552         udev_enumerate_unref(e);
553         return 0;
554
555 fail:
556         if (e)
557                 udev_enumerate_unref(e);
558
559         device_shutdown(m);
560         return r;
561 }
562
563 void device_fd_event(Manager *m, int events) {
564         struct udev_device *dev;
565         int r;
566         const char *action, *ready;
567
568         assert(m);
569
570         if (events != EPOLLIN) {
571                 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
572
573                 if (!ratelimit_test(&limit))
574                         log_error("Failed to get udev event: %m");
575                 if (!(events & EPOLLIN))
576                         return;
577         }
578
579         if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
580                 /*
581                  * libudev might filter-out devices which pass the bloom filter,
582                  * so getting NULL here is not necessarily an error
583                  */
584                 return;
585         }
586
587         if (!(action = udev_device_get_action(dev))) {
588                 log_error("Failed to get udev action string.");
589                 goto fail;
590         }
591
592         ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
593
594         if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
595                 if ((r = device_process_removed_device(m, dev)) < 0) {
596                         log_error("Failed to process udev device event: %s", strerror(-r));
597                         goto fail;
598                 }
599         } else {
600                 if ((r = device_process_new_device(m, dev, true)) < 0) {
601                         log_error("Failed to process udev device event: %s", strerror(-r));
602                         goto fail;
603                 }
604         }
605
606 fail:
607         udev_device_unref(dev);
608 }
609
610 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
611         [DEVICE_DEAD] = "dead",
612         [DEVICE_PLUGGED] = "plugged"
613 };
614
615 DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
616
617 const UnitVTable device_vtable = {
618         .object_size = sizeof(Device),
619         .sections =
620                 "Unit\0"
621                 "Device\0"
622                 "Install\0",
623
624         .no_instances = true,
625
626         .init = device_init,
627
628         .load = unit_load_fragment_and_dropin_optional,
629         .done = device_done,
630         .coldplug = device_coldplug,
631
632         .dump = device_dump,
633
634         .active_state = device_active_state,
635         .sub_state_to_string = device_sub_state_to_string,
636
637         .bus_interface = "org.freedesktop.systemd1.Device",
638         .bus_message_handler = bus_device_message_handler,
639         .bus_invalidating_properties =  bus_device_invalidating_properties,
640
641         .following = device_following,
642         .following_set = device_following_set,
643
644         .enumerate = device_enumerate,
645         .shutdown = device_shutdown,
646
647         .status_message_formats = {
648                 .starting_stopping = {
649                         [0] = "Expecting device %s...",
650                 },
651                 .finished_start_job = {
652                         [JOB_DONE]       = "Found device %s.",
653                         [JOB_TIMEOUT]    = "Timed out waiting for device %s.",
654                 },
655         },
656 };