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