]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/device.c
logind: drop "interactive" parameter from SetRebootToFirmwareSetup() bus call
[thirdparty/systemd.git] / src / core / device.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5cb5a6ff 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
25ac040b 22#include <errno.h>
f94ea366 23#include <sys/epoll.h>
25ac040b
LP
24#include <libudev.h>
25
25ac040b 26#include "log.h"
9e2f7c11 27#include "unit-name.h"
4139c1b2 28#include "dbus-device.h"
9eb977db 29#include "path-util.h"
718db961 30#include "udev-util.h"
9670d583
LP
31#include "unit.h"
32#include "swap.h"
33#include "device.h"
5cb5a6ff 34
f50e0a01
LP
35static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
36 [DEVICE_DEAD] = UNIT_INACTIVE,
628c89cc
LP
37 [DEVICE_TENTATIVE] = UNIT_ACTIVATING,
38 [DEVICE_PLUGGED] = UNIT_ACTIVE,
f50e0a01
LP
39};
40
718db961
LP
41static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
42
8fe914ec 43static void device_unset_sysfs(Device *d) {
f1421cc6 44 Hashmap *devices;
8fe914ec
LP
45 Device *first;
46
47 assert(d);
48
a7f241db
LP
49 if (!d->sysfs)
50 return;
51
52 /* Remove this unit from the chain of devices which share the
53 * same sysfs path. */
f1421cc6
LP
54 devices = UNIT(d)->manager->devices_by_sysfs;
55 first = hashmap_get(devices, d->sysfs);
71fda00f 56 LIST_REMOVE(same_sysfs, first, d);
8fe914ec 57
a7f241db 58 if (first)
f1421cc6 59 hashmap_remove_and_replace(devices, d->sysfs, first->sysfs, first);
a7f241db 60 else
f1421cc6 61 hashmap_remove(devices, d->sysfs);
a7f241db
LP
62
63 free(d->sysfs);
64 d->sysfs = NULL;
8fe914ec
LP
65}
66
628c89cc
LP
67static int device_set_sysfs(Device *d, const char *sysfs) {
68 Device *first;
69 char *copy;
70 int r;
71
72 assert(d);
73
74 if (streq_ptr(d->sysfs, sysfs))
75 return 0;
76
77 r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops);
78 if (r < 0)
79 return r;
80
81 copy = strdup(sysfs);
82 if (!copy)
83 return -ENOMEM;
84
85 device_unset_sysfs(d);
86
87 first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
88 LIST_PREPEND(same_sysfs, first, d);
89
90 r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
91 if (r < 0) {
92 LIST_REMOVE(same_sysfs, first, d);
93 free(copy);
94 return r;
95 }
96
97 d->sysfs = copy;
98
99 return 0;
100}
101
faf919f1
LP
102static void device_init(Unit *u) {
103 Device *d = DEVICE(u);
104
105 assert(d);
1124fe6f 106 assert(UNIT(d)->load_state == UNIT_STUB);
faf919f1 107
8fe914ec
LP
108 /* In contrast to all other unit types we timeout jobs waiting
109 * for devices by default. This is because they otherwise wait
35b8ca3a 110 * indefinitely for plugged in devices, something which cannot
8fe914ec
LP
111 * happen for the other units since their operations time out
112 * anyway. */
f1421cc6 113 u->job_timeout = u->manager->default_timeout_start_usec;
c8f4d764 114
f1421cc6
LP
115 u->ignore_on_isolate = true;
116 u->ignore_on_snapshot = true;
faf919f1
LP
117}
118
87f0e418
LP
119static void device_done(Unit *u) {
120 Device *d = DEVICE(u);
034c6ed7
LP
121
122 assert(d);
e537352b 123
8fe914ec 124 device_unset_sysfs(d);
e537352b
LP
125}
126
f50e0a01
LP
127static void device_set_state(Device *d, DeviceState state) {
128 DeviceState old_state;
129 assert(d);
5cb5a6ff 130
f50e0a01
LP
131 old_state = d->state;
132 d->state = state;
5cb5a6ff 133
e537352b 134 if (state != old_state)
79008bdd 135 log_unit_debug(UNIT(d)->id,
66870f90
ZJS
136 "%s changed %s -> %s", UNIT(d)->id,
137 device_state_to_string(old_state),
138 device_state_to_string(state));
f50e0a01 139
e2f3b44c 140 unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
f50e0a01
LP
141}
142
6e392c9c 143static int device_coldplug(Unit *u, Hashmap *deferred_work) {
f50e0a01
LP
144 Device *d = DEVICE(u);
145
146 assert(d);
147 assert(d->state == DEVICE_DEAD);
148
628c89cc
LP
149 if (d->found & DEVICE_FOUND_UDEV)
150 /* If udev says the device is around, it's around */
73608ed9 151 device_set_state(d, DEVICE_PLUGGED);
628c89cc
LP
152 else if (d->found != DEVICE_NOT_FOUND)
153 /* If a device is found in /proc/self/mountinfo or
154 * /proc/swaps, it's "tentatively" around. */
155 device_set_state(d, DEVICE_TENTATIVE);
f50e0a01
LP
156
157 return 0;
158}
159
160static void device_dump(Unit *u, FILE *f, const char *prefix) {
25ac040b 161 Device *d = DEVICE(u);
5cb5a6ff 162
25ac040b 163 assert(d);
5cb5a6ff
LP
164
165 fprintf(f,
25ac040b
LP
166 "%sDevice State: %s\n"
167 "%sSysfs Path: %s\n",
a16e1123 168 prefix, device_state_to_string(d->state),
f50e0a01
LP
169 prefix, strna(d->sysfs));
170}
171
44a6b1b6 172_pure_ static UnitActiveState device_active_state(Unit *u) {
f50e0a01
LP
173 assert(u);
174
175 return state_translation_table[DEVICE(u)->state];
25ac040b
LP
176}
177
44a6b1b6 178_pure_ static const char *device_sub_state_to_string(Unit *u) {
10a94420
LP
179 assert(u);
180
a16e1123 181 return device_state_to_string(DEVICE(u)->state);
10a94420
LP
182}
183
628c89cc 184static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
965e5c5d 185 const char *model;
628c89cc 186 int r;
965e5c5d
LP
187
188 assert(u);
189 assert(dev);
190 assert(path);
191
192 model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
193 if (!model)
194 model = udev_device_get_property_value(dev, "ID_MODEL");
195
196 if (model) {
197 const char *label;
198
199 /* Try to concatenate the device model string with a label, if there is one */
200 label = udev_device_get_property_value(dev, "ID_FS_LABEL");
201 if (!label)
202 label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
203 if (!label)
204 label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
205
206 if (label) {
207 _cleanup_free_ char *j;
208
209 j = strjoin(model, " ", label, NULL);
210 if (j)
628c89cc 211 r = unit_set_description(u, j);
c43b2132
TA
212 else
213 r = -ENOMEM;
628c89cc
LP
214 } else
215 r = unit_set_description(u, model);
216 } else
217 r = unit_set_description(u, path);
965e5c5d 218
628c89cc
LP
219 if (r < 0)
220 log_unit_error_errno(u->id, r, "Failed to set device description: %m");
965e5c5d 221
628c89cc 222 return r;
965e5c5d
LP
223}
224
225static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
226 const char *wants;
a2a5291b 227 const char *word, *state;
965e5c5d
LP
228 size_t l;
229 int r;
b2fadec6 230 const char *property;
965e5c5d
LP
231
232 assert(u);
233 assert(dev);
234
b2fadec6
ZJS
235 property = u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
236 wants = udev_device_get_property_value(dev, property);
965e5c5d
LP
237 if (!wants)
238 return 0;
239
a2a5291b 240 FOREACH_WORD_QUOTED(word, l, wants, state) {
965e5c5d
LP
241 _cleanup_free_ char *n = NULL;
242 char e[l+1];
243
a2a5291b 244 memcpy(e, word, l);
965e5c5d
LP
245 e[l] = 0;
246
247 n = unit_name_mangle(e, MANGLE_NOGLOB);
248 if (!n)
628c89cc 249 return log_oom();
965e5c5d
LP
250
251 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
252 if (r < 0)
628c89cc 253 return log_unit_error_errno(u->id, r, "Failed to add wants dependency: %m");
965e5c5d 254 }
b2fadec6 255 if (!isempty(state))
628c89cc 256 log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.", property, strna(udev_device_get_syspath(dev)));
965e5c5d
LP
257
258 return 0;
259}
260
628c89cc
LP
261static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
262 _cleanup_free_ char *e = NULL;
965e5c5d 263 const char *sysfs;
25ac040b 264 Unit *u = NULL;
25ac040b 265 bool delete;
965e5c5d 266 int r;
25ac040b
LP
267
268 assert(m);
965e5c5d
LP
269 assert(dev);
270 assert(path);
25ac040b 271
b47d419c
ZJS
272 sysfs = udev_device_get_syspath(dev);
273 if (!sysfs)
f1421cc6 274 return 0;
7f275a9f 275
628c89cc
LP
276 e = unit_name_from_path(path, ".device");
277 if (!e)
278 return log_oom();
279
280 u = manager_get_unit(m, e);
25ac040b 281
628c89cc
LP
282 if (u &&
283 DEVICE(u)->sysfs &&
284 !path_equal(DEVICE(u)->sysfs, sysfs)) {
285 log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs);
8fe914ec 286 return -EEXIST;
628c89cc 287 }
25ac040b 288
aab14b13
LP
289 if (!u) {
290 delete = true;
291
7d17cfbc
MS
292 u = unit_new(m, sizeof(Device));
293 if (!u)
f1421cc6 294 return log_oom();
25ac040b 295
628c89cc 296 r = unit_add_name(u, e);
7d17cfbc 297 if (r < 0)
25ac040b
LP
298 goto fail;
299
ee6cb288
LP
300 unit_add_to_load_queue(u);
301 } else
302 delete = false;
303
304 /* If this was created via some dependency and has not
305 * actually been seen yet ->sysfs will not be
306 * initialized. Hence initialize it if necessary. */
307
628c89cc
LP
308 r = device_set_sysfs(DEVICE(u), sysfs);
309 if (r < 0)
310 goto fail;
aab14b13 311
628c89cc 312 (void) device_update_description(u, dev, path);
25ac040b 313
628c89cc
LP
314 /* The additional systemd udev properties we only interpret
315 * for the main object */
316 if (main)
317 (void) device_add_udev_wants(u, dev);
f94ea366 318
f1421cc6
LP
319 /* Note that this won't dispatch the load queue, the caller
320 * has to do that if needed and appropriate */
321
c1e1601e 322 unit_add_to_dbus_queue(u);
25ac040b
LP
323 return 0;
324
325fail:
628c89cc 326 log_unit_warning_errno(u->id, r, "Failed to set up device unit: %m");
ee5f3479 327
25ac040b
LP
328 if (delete && u)
329 unit_free(u);
ee5f3479 330
25ac040b
LP
331 return r;
332}
333
628c89cc 334static int device_process_new(Manager *m, struct udev_device *dev) {
f1421cc6 335 const char *sysfs, *dn, *alias;
8fe914ec 336 struct udev_list_entry *item = NULL, *first = NULL;
003ac9d0 337 int r;
8fe914ec
LP
338
339 assert(m);
340
718db961
LP
341 sysfs = udev_device_get_syspath(dev);
342 if (!sysfs)
f1421cc6 343 return 0;
8fe914ec
LP
344
345 /* Add the main unit named after the sysfs path */
628c89cc 346 r = device_setup_unit(m, dev, sysfs, true);
003ac9d0
HH
347 if (r < 0)
348 return r;
8fe914ec
LP
349
350 /* Add an additional unit for the device node */
f1421cc6
LP
351 dn = udev_device_get_devnode(dev);
352 if (dn)
628c89cc 353 (void) device_setup_unit(m, dev, dn, false);
8fe914ec
LP
354
355 /* Add additional units for all symlinks */
356 first = udev_device_get_devlinks_list_entry(dev);
357 udev_list_entry_foreach(item, first) {
358 const char *p;
5845b46b 359 struct stat st;
8fe914ec
LP
360
361 /* Don't bother with the /dev/block links */
362 p = udev_list_entry_get_name(item);
363
364 if (path_startswith(p, "/dev/block/") ||
365 path_startswith(p, "/dev/char/"))
366 continue;
367
5845b46b
LP
368 /* Verify that the symlink in the FS actually belongs
369 * to this device. This is useful to deal with
370 * conflicting devices, e.g. when two disks want the
371 * same /dev/disk/by-label/xxx link because they have
372 * the same label. We want to make sure that the same
373 * device that won the symlink wins in systemd, so we
ee33e53a 374 * check the device node major/minor */
5845b46b
LP
375 if (stat(p, &st) >= 0)
376 if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
377 st.st_rdev != udev_device_get_devnum(dev))
378 continue;
379
628c89cc 380 (void) device_setup_unit(m, dev, p, false);
8fe914ec
LP
381 }
382
f1421cc6
LP
383 /* Add additional units for all explicitly configured
384 * aliases */
385 alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
386 if (alias) {
a2a5291b 387 const char *word, *state;
f1421cc6 388 size_t l;
8fe914ec 389
a2a5291b 390 FOREACH_WORD_QUOTED(word, l, alias, state) {
f1421cc6 391 char e[l+1];
8fe914ec 392
a2a5291b 393 memcpy(e, word, l);
f1421cc6
LP
394 e[l] = 0;
395
396 if (path_is_absolute(e))
628c89cc 397 (void) device_setup_unit(m, dev, e, false);
f1421cc6
LP
398 else
399 log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
400 }
b2fadec6
ZJS
401 if (!isempty(state))
402 log_warning("SYSTEMD_ALIAS for %s has trailing garbage, ignoring.", sysfs);
8fe914ec
LP
403 }
404
405 return 0;
406}
407
628c89cc
LP
408static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
409 DeviceFound n;
410
411 assert(d);
412
413 n = add ? (d->found | found) : (d->found & ~found);
414 if (n == d->found)
415 return;
416
417 d->found = n;
418
419 if (now) {
420 if (d->found & DEVICE_FOUND_UDEV)
421 device_set_state(d, DEVICE_PLUGGED);
496068a8 422 else if (add && d->found != DEVICE_NOT_FOUND)
628c89cc
LP
423 device_set_state(d, DEVICE_TENTATIVE);
424 else
425 device_set_state(d, DEVICE_DEAD);
426 }
427}
428
429static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
f1421cc6 430 Device *d, *l;
25ac040b
LP
431
432 assert(m);
628c89cc 433 assert(sysfs);
25ac040b 434
628c89cc
LP
435 if (found == DEVICE_NOT_FOUND)
436 return 0;
25ac040b 437
f1421cc6
LP
438 l = hashmap_get(m->devices_by_sysfs, sysfs);
439 LIST_FOREACH(same_sysfs, d, l)
628c89cc
LP
440 device_update_found_one(d, add, found, now);
441
442 return 0;
25ac040b
LP
443}
444
628c89cc
LP
445static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
446 _cleanup_free_ char *e = NULL;
447 Unit *u;
f94ea366
LP
448
449 assert(m);
628c89cc 450 assert(path);
f94ea366 451
628c89cc
LP
452 if (found == DEVICE_NOT_FOUND)
453 return 0;
f94ea366 454
628c89cc
LP
455 e = unit_name_from_path(path, ".device");
456 if (!e)
457 return log_oom();
f94ea366 458
628c89cc
LP
459 u = manager_get_unit(m, e);
460 if (!u)
461 return 0;
462
463 device_update_found_one(DEVICE(u), add, found, now);
f94ea366
LP
464 return 0;
465}
466
f1421cc6
LP
467static bool device_is_ready(struct udev_device *dev) {
468 const char *ready;
469
470 assert(dev);
471
472 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
473 if (!ready)
474 return true;
475
476 return parse_boolean(ready) != 0;
477}
478
a7f241db
LP
479static Unit *device_following(Unit *u) {
480 Device *d = DEVICE(u);
481 Device *other, *first = NULL;
482
483 assert(d);
484
ac155bb8 485 if (startswith(u->id, "sys-"))
a7f241db
LP
486 return NULL;
487
488 /* Make everybody follow the unit that's named after the sysfs path */
489 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
1124fe6f 490 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
491 return UNIT(other);
492
493 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
1124fe6f 494 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
495 return UNIT(other);
496
497 first = other;
498 }
499
500 return UNIT(first);
501}
502
f1421cc6
LP
503static int device_following_set(Unit *u, Set **_set) {
504 Device *d = DEVICE(u), *other;
505 Set *set;
6210e7fc
LP
506 int r;
507
508 assert(d);
f1421cc6 509 assert(_set);
6210e7fc 510
f1421cc6
LP
511 if (LIST_JUST_US(same_sysfs, d)) {
512 *_set = NULL;
6210e7fc
LP
513 return 0;
514 }
515
d5099efc 516 set = set_new(NULL);
f1421cc6 517 if (!set)
6210e7fc
LP
518 return -ENOMEM;
519
f1421cc6
LP
520 LIST_FOREACH_AFTER(same_sysfs, other, d) {
521 r = set_put(set, other);
522 if (r < 0)
6210e7fc 523 goto fail;
f1421cc6 524 }
6210e7fc 525
f1421cc6
LP
526 LIST_FOREACH_BEFORE(same_sysfs, other, d) {
527 r = set_put(set, other);
528 if (r < 0)
6210e7fc 529 goto fail;
f1421cc6 530 }
6210e7fc 531
f1421cc6 532 *_set = set;
6210e7fc
LP
533 return 1;
534
535fail:
f1421cc6 536 set_free(set);
6210e7fc
LP
537 return r;
538}
539
25ac040b
LP
540static void device_shutdown(Manager *m) {
541 assert(m);
542
718db961
LP
543 m->udev_event_source = sd_event_source_unref(m->udev_event_source);
544
a16e1123 545 if (m->udev_monitor) {
f94ea366 546 udev_monitor_unref(m->udev_monitor);
a16e1123
LP
547 m->udev_monitor = NULL;
548 }
f94ea366 549
8fe914ec
LP
550 hashmap_free(m->devices_by_sysfs);
551 m->devices_by_sysfs = NULL;
25ac040b
LP
552}
553
554static int device_enumerate(Manager *m) {
718db961 555 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
25ac040b 556 struct udev_list_entry *item = NULL, *first = NULL;
718db961 557 int r;
25ac040b
LP
558
559 assert(m);
560
9670d583 561 if (!m->udev_monitor) {
718db961
LP
562 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
563 if (!m->udev_monitor) {
a16e1123
LP
564 r = -ENOMEM;
565 goto fail;
566 }
f94ea366 567
47ae6e67
LP
568 /* This will fail if we are unprivileged, but that
569 * should not matter much, as user instances won't run
570 * during boot. */
8fa158e7 571 (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
99448c1f 572
718db961
LP
573 r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
574 if (r < 0)
e1ce2c27 575 goto fail;
e1ce2c27 576
718db961
LP
577 r = udev_monitor_enable_receiving(m->udev_monitor);
578 if (r < 0)
a16e1123 579 goto fail;
f94ea366 580
151b9b96 581 r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
718db961
LP
582 if (r < 0)
583 goto fail;
a16e1123 584 }
f94ea366 585
718db961
LP
586 e = udev_enumerate_new(m->udev);
587 if (!e) {
4f2d528d
LP
588 r = -ENOMEM;
589 goto fail;
590 }
718db961
LP
591
592 r = udev_enumerate_add_match_tag(e, "systemd");
593 if (r < 0)
e1ce2c27 594 goto fail;
25ac040b 595
e1202047
LP
596 r = udev_enumerate_add_match_is_initialized(e);
597 if (r < 0)
598 goto fail;
599
718db961
LP
600 r = udev_enumerate_scan_devices(e);
601 if (r < 0)
4f2d528d 602 goto fail;
25ac040b 603
4f2d528d 604 first = udev_enumerate_get_list_entry(e);
628c89cc
LP
605 udev_list_entry_foreach(item, first) {
606 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
607 const char *sysfs;
608
609 sysfs = udev_list_entry_get_name(item);
610
611 dev = udev_device_new_from_syspath(m->udev, sysfs);
612 if (!dev) {
613 log_oom();
614 continue;
615 }
616
617 if (!device_is_ready(dev))
618 continue;
619
620 (void) device_process_new(m, dev);
621
622 device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
623 }
25ac040b 624
25ac040b
LP
625 return 0;
626
627fail:
628c89cc
LP
628 log_error_errno(r, "Failed to enumerate devices: %m");
629
25ac040b
LP
630 device_shutdown(m);
631 return r;
5cb5a6ff
LP
632}
633
718db961
LP
634static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
635 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
718db961 636 Manager *m = userdata;
628c89cc 637 const char *action, *sysfs;
718db961 638 int r;
f94ea366
LP
639
640 assert(m);
99448c1f 641
718db961 642 if (revents != EPOLLIN) {
99448c1f
KS
643 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
644
645 if (!ratelimit_test(&limit))
56f64d95 646 log_error_errno(errno, "Failed to get udev event: %m");
718db961
LP
647 if (!(revents & EPOLLIN))
648 return 0;
99448c1f 649 }
f94ea366 650
718db961
LP
651 /*
652 * libudev might filter-out devices which pass the bloom
653 * filter, so getting NULL here is not necessarily an error.
654 */
655 dev = udev_monitor_receive_device(m->udev_monitor);
656 if (!dev)
657 return 0;
f94ea366 658
628c89cc
LP
659 sysfs = udev_device_get_syspath(dev);
660 if (!sysfs) {
661 log_error("Failed to get udev sys path.");
662 return 0;
663 }
664
718db961
LP
665 action = udev_device_get_action(dev);
666 if (!action) {
f94ea366 667 log_error("Failed to get udev action string.");
718db961 668 return 0;
f94ea366
LP
669 }
670
628c89cc
LP
671 if (streq(action, "remove")) {
672 r = swap_process_device_remove(m, dev);
9670d583 673 if (r < 0)
da927ba9 674 log_error_errno(r, "Failed to process swap device remove event: %m");
9670d583 675
628c89cc
LP
676 /* If we get notified that a device was removed by
677 * udev, then it's completely gone, hence unset all
678 * found bits */
679 device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
f1421cc6 680
628c89cc
LP
681 } else if (device_is_ready(dev)) {
682
683 (void) device_process_new(m, dev);
684
685 r = swap_process_device_new(m, dev);
9670d583 686 if (r < 0)
da927ba9 687 log_error_errno(r, "Failed to process swap device new event: %m");
9670d583 688
f1421cc6
LP
689 manager_dispatch_load_queue(m);
690
628c89cc
LP
691 /* The device is found now, set the udev found bit */
692 device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
693
694 } else {
695 /* The device is nominally around, but not ready for
696 * us. Hence unset the udev bit, but leave the rest
697 * around. */
698
699 device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
f94ea366
LP
700 }
701
718db961 702 return 0;
f94ea366
LP
703}
704
0faacd47
LP
705static bool device_supported(Manager *m) {
706 static int read_only = -1;
707 assert(m);
708
709 /* If /sys is read-only we don't support device units, and any
710 * attempts to start one should fail immediately. */
711
712 if (read_only < 0)
713 read_only = path_is_read_only_fs("/sys");
714
715 return read_only <= 0;
716}
717
628c89cc
LP
718int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
719 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
720 struct stat st;
721
722 assert(m);
723 assert(node);
724
725 /* This is called whenever we find a device referenced in
726 * /proc/swaps or /proc/self/mounts. Such a device might be
727 * mounted/enabled at a time where udev has not finished
728 * probing it yet, and we thus haven't learned about it
729 * yet. In this case we will set the device unit to
730 * "tentative" state. */
731
732 if (add) {
733 if (!path_startswith(node, "/dev"))
734 return 0;
735
736 if (stat(node, &st) < 0) {
737 if (errno == ENOENT)
738 return 0;
739
740 return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
741 }
742
743 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
744 return 0;
745
746 dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
747 if (!dev) {
748 if (errno == ENOENT)
749 return 0;
750
751 return log_oom();
752 }
753
754 /* If the device is known in the kernel and newly
755 * appeared, then we'll create a device unit for it,
756 * under the name referenced in /proc/swaps or
757 * /proc/self/mountinfo. */
758
759 (void) device_setup_unit(m, dev, node, false);
760 }
761
762 /* Update the device unit's state, should it exist */
763 return device_update_found_by_name(m, node, add, found, now);
764}
765
a16e1123
LP
766static const char* const device_state_table[_DEVICE_STATE_MAX] = {
767 [DEVICE_DEAD] = "dead",
628c89cc
LP
768 [DEVICE_TENTATIVE] = "tentative",
769 [DEVICE_PLUGGED] = "plugged",
a16e1123
LP
770};
771
772DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
773
87f0e418 774const UnitVTable device_vtable = {
7d17cfbc 775 .object_size = sizeof(Device),
f975e971
LP
776 .sections =
777 "Unit\0"
778 "Device\0"
779 "Install\0",
5cb5a6ff 780
9e2f7c11
LP
781 .no_instances = true,
782
faf919f1 783 .init = device_init,
034c6ed7 784 .done = device_done,
718db961
LP
785 .load = unit_load_fragment_and_dropin_optional,
786
f50e0a01
LP
787 .coldplug = device_coldplug,
788
5cb5a6ff
LP
789 .dump = device_dump,
790
f50e0a01 791 .active_state = device_active_state,
10a94420 792 .sub_state_to_string = device_sub_state_to_string,
25ac040b 793
c4e2ceae 794 .bus_interface = "org.freedesktop.systemd1.Device",
718db961 795 .bus_vtable = bus_device_vtable,
4139c1b2 796
a7f241db 797 .following = device_following,
6210e7fc 798 .following_set = device_following_set,
a7f241db 799
f50e0a01 800 .enumerate = device_enumerate,
c6918296 801 .shutdown = device_shutdown,
0faacd47 802 .supported = device_supported,
c6918296
MS
803
804 .status_message_formats = {
805 .starting_stopping = {
806 [0] = "Expecting device %s...",
807 },
808 .finished_start_job = {
809 [JOB_DONE] = "Found device %s.",
810 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
811 },
812 },
5cb5a6ff 813};