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