]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/device.c
api: in constructor function calls, always put the returned object pointer first...
[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
5cb5a6ff 26#include "strv.h"
25ac040b 27#include "log.h"
9e2f7c11 28#include "unit-name.h"
4139c1b2 29#include "dbus-device.h"
f6a6225e 30#include "def.h"
9eb977db 31#include "path-util.h"
718db961 32#include "udev-util.h"
9670d583
LP
33#include "unit.h"
34#include "swap.h"
35#include "device.h"
5cb5a6ff 36
f50e0a01
LP
37static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
38 [DEVICE_DEAD] = UNIT_INACTIVE,
73608ed9 39 [DEVICE_PLUGGED] = UNIT_ACTIVE
f50e0a01
LP
40};
41
718db961
LP
42static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
43
8fe914ec 44static void device_unset_sysfs(Device *d) {
f1421cc6 45 Hashmap *devices;
8fe914ec
LP
46 Device *first;
47
48 assert(d);
49
a7f241db
LP
50 if (!d->sysfs)
51 return;
52
53 /* Remove this unit from the chain of devices which share the
54 * same sysfs path. */
f1421cc6
LP
55 devices = UNIT(d)->manager->devices_by_sysfs;
56 first = hashmap_get(devices, d->sysfs);
71fda00f 57 LIST_REMOVE(same_sysfs, first, d);
8fe914ec 58
a7f241db 59 if (first)
f1421cc6 60 hashmap_remove_and_replace(devices, d->sysfs, first->sysfs, first);
a7f241db 61 else
f1421cc6 62 hashmap_remove(devices, d->sysfs);
a7f241db
LP
63
64 free(d->sysfs);
65 d->sysfs = NULL;
8fe914ec
LP
66}
67
faf919f1
LP
68static void device_init(Unit *u) {
69 Device *d = DEVICE(u);
70
71 assert(d);
1124fe6f 72 assert(UNIT(d)->load_state == UNIT_STUB);
faf919f1 73
8fe914ec
LP
74 /* In contrast to all other unit types we timeout jobs waiting
75 * for devices by default. This is because they otherwise wait
35b8ca3a 76 * indefinitely for plugged in devices, something which cannot
8fe914ec
LP
77 * happen for the other units since their operations time out
78 * anyway. */
f1421cc6 79 u->job_timeout = u->manager->default_timeout_start_usec;
c8f4d764 80
f1421cc6
LP
81 u->ignore_on_isolate = true;
82 u->ignore_on_snapshot = true;
faf919f1
LP
83}
84
87f0e418
LP
85static void device_done(Unit *u) {
86 Device *d = DEVICE(u);
034c6ed7
LP
87
88 assert(d);
e537352b 89
8fe914ec 90 device_unset_sysfs(d);
e537352b
LP
91}
92
f50e0a01
LP
93static void device_set_state(Device *d, DeviceState state) {
94 DeviceState old_state;
95 assert(d);
5cb5a6ff 96
f50e0a01
LP
97 old_state = d->state;
98 d->state = state;
5cb5a6ff 99
e537352b 100 if (state != old_state)
66870f90
ZJS
101 log_debug_unit(UNIT(d)->id,
102 "%s changed %s -> %s", UNIT(d)->id,
103 device_state_to_string(old_state),
104 device_state_to_string(state));
f50e0a01 105
e2f3b44c 106 unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
f50e0a01
LP
107}
108
109static int device_coldplug(Unit *u) {
110 Device *d = DEVICE(u);
111
112 assert(d);
113 assert(d->state == DEVICE_DEAD);
114
115 if (d->sysfs)
73608ed9 116 device_set_state(d, DEVICE_PLUGGED);
f50e0a01
LP
117
118 return 0;
119}
120
121static void device_dump(Unit *u, FILE *f, const char *prefix) {
25ac040b 122 Device *d = DEVICE(u);
5cb5a6ff 123
25ac040b 124 assert(d);
5cb5a6ff
LP
125
126 fprintf(f,
25ac040b
LP
127 "%sDevice State: %s\n"
128 "%sSysfs Path: %s\n",
a16e1123 129 prefix, device_state_to_string(d->state),
f50e0a01
LP
130 prefix, strna(d->sysfs));
131}
132
44a6b1b6 133_pure_ static UnitActiveState device_active_state(Unit *u) {
f50e0a01
LP
134 assert(u);
135
136 return state_translation_table[DEVICE(u)->state];
25ac040b
LP
137}
138
44a6b1b6 139_pure_ static const char *device_sub_state_to_string(Unit *u) {
10a94420
LP
140 assert(u);
141
a16e1123 142 return device_state_to_string(DEVICE(u)->state);
10a94420
LP
143}
144
8fe914ec 145static int device_add_escaped_name(Unit *u, const char *dn) {
718db961 146 _cleanup_free_ char *e = NULL;
25ac040b
LP
147 int r;
148
149 assert(u);
150 assert(dn);
151 assert(dn[0] == '/');
152
b0193f1c
LP
153 e = unit_name_from_path(dn, ".device");
154 if (!e)
25ac040b
LP
155 return -ENOMEM;
156
157 r = unit_add_name(u, e);
25ac040b
LP
158 if (r < 0 && r != -EEXIST)
159 return r;
160
161 return 0;
162}
163
aab14b13 164static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
718db961 165 _cleanup_free_ char *e = NULL;
aab14b13
LP
166 Unit *u;
167
168 assert(m);
169 assert(dn);
170 assert(dn[0] == '/');
171 assert(_u);
172
b0193f1c
LP
173 e = unit_name_from_path(dn, ".device");
174 if (!e)
aab14b13
LP
175 return -ENOMEM;
176
177 u = manager_get_unit(m, e);
aab14b13
LP
178 if (u) {
179 *_u = u;
180 return 1;
181 }
182
183 return 0;
184}
185
8fe914ec
LP
186static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
187 const char *sysfs, *model;
25ac040b
LP
188 Unit *u = NULL;
189 int r;
25ac040b 190 bool delete;
25ac040b
LP
191
192 assert(m);
193
b47d419c
ZJS
194 sysfs = udev_device_get_syspath(dev);
195 if (!sysfs)
f1421cc6 196 return 0;
7f275a9f 197
b47d419c
ZJS
198 r = device_find_escape_name(m, path, &u);
199 if (r < 0)
aab14b13 200 return r;
25ac040b 201
5845b46b 202 if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
8fe914ec 203 return -EEXIST;
25ac040b 204
aab14b13
LP
205 if (!u) {
206 delete = true;
207
7d17cfbc
MS
208 u = unit_new(m, sizeof(Device));
209 if (!u)
f1421cc6 210 return log_oom();
25ac040b 211
7d17cfbc
MS
212 r = device_add_escaped_name(u, path);
213 if (r < 0)
25ac040b
LP
214 goto fail;
215
ee6cb288
LP
216 unit_add_to_load_queue(u);
217 } else
218 delete = false;
219
220 /* If this was created via some dependency and has not
221 * actually been seen yet ->sysfs will not be
222 * initialized. Hence initialize it if necessary. */
223
224 if (!DEVICE(u)->sysfs) {
225 Device *first;
226
718db961
LP
227 DEVICE(u)->sysfs = strdup(sysfs);
228 if (!DEVICE(u)->sysfs) {
25ac040b
LP
229 r = -ENOMEM;
230 goto fail;
231 }
232
718db961
LP
233 r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func);
234 if (r < 0)
235 goto fail;
25ac040b 236
8fe914ec 237 first = hashmap_get(m->devices_by_sysfs, sysfs);
71fda00f 238 LIST_PREPEND(same_sysfs, first, DEVICE(u));
8fe914ec 239
b47d419c
ZJS
240 r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
241 if (r < 0)
25ac040b 242 goto fail;
ee6cb288 243 }
8fe914ec 244
aab14b13 245 if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
718db961 246 (model = udev_device_get_property_value(dev, "ID_MODEL")))
b47d419c 247 r = unit_set_description(u, model);
718db961 248 else
b47d419c 249 r = unit_set_description(u, path);
718db961
LP
250 if (r < 0)
251 goto fail;
aab14b13 252
8fe914ec 253 if (main) {
f1421cc6
LP
254 const char *wants;
255
8fe914ec
LP
256 /* The additional systemd udev properties we only
257 * interpret for the main object */
25ac040b 258
718db961 259 wants = udev_device_get_property_value(dev, m->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS");
07845c14 260 if (wants) {
8fe914ec
LP
261 char *state, *w;
262 size_t l;
25ac040b 263
8fe914ec 264 FOREACH_WORD_QUOTED(w, l, wants, state) {
f1421cc6
LP
265 _cleanup_free_ char *n = NULL;
266 char e[l+1];
8fe914ec 267
f1421cc6 268 memcpy(e, w, l);
c5ab2e02 269 e[l] = 0;
b47d419c 270
f78e6385 271 n = unit_name_mangle(e, MANGLE_NOGLOB);
d9abd149
MT
272 if (!n) {
273 r = -ENOMEM;
274 goto fail;
275 }
d9abd149
MT
276
277 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
8fe914ec
LP
278 if (r < 0)
279 goto fail;
280 }
25ac040b 281 }
a7f241db 282 }
f94ea366 283
f1421cc6
LP
284 /* Note that this won't dispatch the load queue, the caller
285 * has to do that if needed and appropriate */
286
c1e1601e 287 unit_add_to_dbus_queue(u);
25ac040b
LP
288 return 0;
289
290fail:
ee5f3479
LP
291 log_warning("Failed to load device unit: %s", strerror(-r));
292
25ac040b
LP
293 if (delete && u)
294 unit_free(u);
ee5f3479 295
25ac040b
LP
296 return r;
297}
298
f1421cc6
LP
299static int device_process_new_device(Manager *m, struct udev_device *dev) {
300 const char *sysfs, *dn, *alias;
8fe914ec 301 struct udev_list_entry *item = NULL, *first = NULL;
003ac9d0 302 int r;
8fe914ec
LP
303
304 assert(m);
305
718db961
LP
306 sysfs = udev_device_get_syspath(dev);
307 if (!sysfs)
f1421cc6 308 return 0;
8fe914ec
LP
309
310 /* Add the main unit named after the sysfs path */
003ac9d0
HH
311 r = device_update_unit(m, dev, sysfs, true);
312 if (r < 0)
313 return r;
8fe914ec
LP
314
315 /* Add an additional unit for the device node */
f1421cc6
LP
316 dn = udev_device_get_devnode(dev);
317 if (dn)
8fe914ec
LP
318 device_update_unit(m, dev, dn, false);
319
320 /* Add additional units for all symlinks */
321 first = udev_device_get_devlinks_list_entry(dev);
322 udev_list_entry_foreach(item, first) {
323 const char *p;
5845b46b 324 struct stat st;
8fe914ec
LP
325
326 /* Don't bother with the /dev/block links */
327 p = udev_list_entry_get_name(item);
328
329 if (path_startswith(p, "/dev/block/") ||
330 path_startswith(p, "/dev/char/"))
331 continue;
332
5845b46b
LP
333 /* Verify that the symlink in the FS actually belongs
334 * to this device. This is useful to deal with
335 * conflicting devices, e.g. when two disks want the
336 * same /dev/disk/by-label/xxx link because they have
337 * the same label. We want to make sure that the same
338 * device that won the symlink wins in systemd, so we
339 * check the device node major/minor*/
340 if (stat(p, &st) >= 0)
341 if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
342 st.st_rdev != udev_device_get_devnum(dev))
343 continue;
344
8fe914ec
LP
345 device_update_unit(m, dev, p, false);
346 }
347
f1421cc6
LP
348 /* Add additional units for all explicitly configured
349 * aliases */
350 alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
351 if (alias) {
352 char *state, *w;
353 size_t l;
8fe914ec 354
f1421cc6
LP
355 FOREACH_WORD_QUOTED(w, l, alias, state) {
356 char e[l+1];
8fe914ec 357
f1421cc6
LP
358 memcpy(e, w, l);
359 e[l] = 0;
360
361 if (path_is_absolute(e))
362 device_update_unit(m, dev, e, false);
363 else
364 log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
365 }
8fe914ec
LP
366 }
367
368 return 0;
369}
370
f1421cc6
LP
371static void device_set_path_plugged(Manager *m, struct udev_device *dev) {
372 const char *sysfs;
373 Device *d, *l;
25ac040b
LP
374
375 assert(m);
f1421cc6 376 assert(dev);
25ac040b 377
f1421cc6
LP
378 sysfs = udev_device_get_syspath(dev);
379 if (!sysfs)
380 return;
25ac040b 381
f1421cc6
LP
382 l = hashmap_get(m->devices_by_sysfs, sysfs);
383 LIST_FOREACH(same_sysfs, d, l)
384 device_set_state(d, DEVICE_PLUGGED);
25ac040b
LP
385}
386
f94ea366
LP
387static int device_process_removed_device(Manager *m, struct udev_device *dev) {
388 const char *sysfs;
f94ea366
LP
389 Device *d;
390
391 assert(m);
392 assert(dev);
393
f1421cc6
LP
394 sysfs = udev_device_get_syspath(dev);
395 if (!sysfs)
f94ea366
LP
396 return -ENOMEM;
397
8fe914ec
LP
398 /* Remove all units of this sysfs path */
399 while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
400 device_unset_sysfs(d);
401 device_set_state(d, DEVICE_DEAD);
402 }
f94ea366 403
f94ea366
LP
404 return 0;
405}
406
f1421cc6
LP
407static bool device_is_ready(struct udev_device *dev) {
408 const char *ready;
409
410 assert(dev);
411
412 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
413 if (!ready)
414 return true;
415
416 return parse_boolean(ready) != 0;
417}
418
419static int device_process_new_path(Manager *m, const char *path) {
420 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
421
422 assert(m);
423 assert(path);
424
425 dev = udev_device_new_from_syspath(m->udev, path);
426 if (!dev)
427 return log_oom();
428
429 if (!device_is_ready(dev))
430 return 0;
431
432 return device_process_new_device(m, dev);
433}
434
a7f241db
LP
435static Unit *device_following(Unit *u) {
436 Device *d = DEVICE(u);
437 Device *other, *first = NULL;
438
439 assert(d);
440
ac155bb8 441 if (startswith(u->id, "sys-"))
a7f241db
LP
442 return NULL;
443
444 /* Make everybody follow the unit that's named after the sysfs path */
445 for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
1124fe6f 446 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
447 return UNIT(other);
448
449 for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
1124fe6f 450 if (startswith(UNIT(other)->id, "sys-"))
a7f241db
LP
451 return UNIT(other);
452
453 first = other;
454 }
455
456 return UNIT(first);
457}
458
f1421cc6
LP
459static int device_following_set(Unit *u, Set **_set) {
460 Device *d = DEVICE(u), *other;
461 Set *set;
6210e7fc
LP
462 int r;
463
464 assert(d);
f1421cc6 465 assert(_set);
6210e7fc 466
f1421cc6
LP
467 if (LIST_JUST_US(same_sysfs, d)) {
468 *_set = NULL;
6210e7fc
LP
469 return 0;
470 }
471
f1421cc6
LP
472 set = set_new(NULL, NULL);
473 if (!set)
6210e7fc
LP
474 return -ENOMEM;
475
f1421cc6
LP
476 LIST_FOREACH_AFTER(same_sysfs, other, d) {
477 r = set_put(set, other);
478 if (r < 0)
6210e7fc 479 goto fail;
f1421cc6 480 }
6210e7fc 481
f1421cc6
LP
482 LIST_FOREACH_BEFORE(same_sysfs, other, d) {
483 r = set_put(set, other);
484 if (r < 0)
6210e7fc 485 goto fail;
f1421cc6 486 }
6210e7fc 487
f1421cc6 488 *_set = set;
6210e7fc
LP
489 return 1;
490
491fail:
f1421cc6 492 set_free(set);
6210e7fc
LP
493 return r;
494}
495
25ac040b
LP
496static void device_shutdown(Manager *m) {
497 assert(m);
498
718db961
LP
499 m->udev_event_source = sd_event_source_unref(m->udev_event_source);
500
a16e1123 501 if (m->udev_monitor) {
f94ea366 502 udev_monitor_unref(m->udev_monitor);
a16e1123
LP
503 m->udev_monitor = NULL;
504 }
f94ea366 505
8fe914ec
LP
506 hashmap_free(m->devices_by_sysfs);
507 m->devices_by_sysfs = NULL;
25ac040b
LP
508}
509
510static int device_enumerate(Manager *m) {
718db961 511 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
25ac040b 512 struct udev_list_entry *item = NULL, *first = NULL;
718db961 513 int r;
25ac040b
LP
514
515 assert(m);
516
9670d583 517 if (!m->udev_monitor) {
718db961
LP
518 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
519 if (!m->udev_monitor) {
a16e1123
LP
520 r = -ENOMEM;
521 goto fail;
522 }
f94ea366 523
47ae6e67
LP
524 /* This will fail if we are unprivileged, but that
525 * should not matter much, as user instances won't run
526 * during boot. */
527 udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
99448c1f 528
718db961
LP
529 r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
530 if (r < 0)
e1ce2c27 531 goto fail;
e1ce2c27 532
718db961
LP
533 r = udev_monitor_enable_receiving(m->udev_monitor);
534 if (r < 0)
a16e1123 535 goto fail;
f94ea366 536
151b9b96 537 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
538 if (r < 0)
539 goto fail;
a16e1123 540 }
f94ea366 541
718db961
LP
542 e = udev_enumerate_new(m->udev);
543 if (!e) {
4f2d528d
LP
544 r = -ENOMEM;
545 goto fail;
546 }
718db961
LP
547
548 r = udev_enumerate_add_match_tag(e, "systemd");
549 if (r < 0)
e1ce2c27 550 goto fail;
25ac040b 551
e1202047
LP
552 r = udev_enumerate_add_match_is_initialized(e);
553 if (r < 0)
554 goto fail;
555
718db961
LP
556 r = udev_enumerate_scan_devices(e);
557 if (r < 0)
4f2d528d 558 goto fail;
25ac040b 559
4f2d528d
LP
560 first = udev_enumerate_get_list_entry(e);
561 udev_list_entry_foreach(item, first)
f1421cc6 562 device_process_new_path(m, udev_list_entry_get_name(item));
25ac040b 563
25ac040b
LP
564 return 0;
565
566fail:
25ac040b
LP
567 device_shutdown(m);
568 return r;
5cb5a6ff
LP
569}
570
718db961
LP
571static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
572 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
718db961 573 Manager *m = userdata;
f1421cc6 574 const char *action;
718db961 575 int r;
f94ea366
LP
576
577 assert(m);
99448c1f 578
718db961 579 if (revents != EPOLLIN) {
99448c1f
KS
580 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
581
582 if (!ratelimit_test(&limit))
583 log_error("Failed to get udev event: %m");
718db961
LP
584 if (!(revents & EPOLLIN))
585 return 0;
99448c1f 586 }
f94ea366 587
718db961
LP
588 /*
589 * libudev might filter-out devices which pass the bloom
590 * filter, so getting NULL here is not necessarily an error.
591 */
592 dev = udev_monitor_receive_device(m->udev_monitor);
593 if (!dev)
594 return 0;
f94ea366 595
718db961
LP
596 action = udev_device_get_action(dev);
597 if (!action) {
f94ea366 598 log_error("Failed to get udev action string.");
718db961 599 return 0;
f94ea366
LP
600 }
601
f1421cc6 602 if (streq(action, "remove") || !device_is_ready(dev)) {
718db961
LP
603 r = device_process_removed_device(m, dev);
604 if (r < 0)
f1421cc6 605 log_error("Failed to process device remove event: %s", strerror(-r));
9670d583
LP
606
607 r = swap_process_removed_device(m, dev);
608 if (r < 0)
609 log_error("Failed to process swap device remove event: %s", strerror(-r));
610
f94ea366 611 } else {
f1421cc6 612 r = device_process_new_device(m, dev);
718db961 613 if (r < 0)
f1421cc6
LP
614 log_error("Failed to process device new event: %s", strerror(-r));
615
9670d583
LP
616 r = swap_process_new_device(m, dev);
617 if (r < 0)
618 log_error("Failed to process swap device new event: %s", strerror(-r));
619
f1421cc6
LP
620 manager_dispatch_load_queue(m);
621
622 device_set_path_plugged(m, dev);
f94ea366
LP
623 }
624
718db961 625 return 0;
f94ea366
LP
626}
627
a16e1123
LP
628static const char* const device_state_table[_DEVICE_STATE_MAX] = {
629 [DEVICE_DEAD] = "dead",
73608ed9 630 [DEVICE_PLUGGED] = "plugged"
a16e1123
LP
631};
632
633DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
634
87f0e418 635const UnitVTable device_vtable = {
7d17cfbc 636 .object_size = sizeof(Device),
f975e971
LP
637 .sections =
638 "Unit\0"
639 "Device\0"
640 "Install\0",
5cb5a6ff 641
9e2f7c11
LP
642 .no_instances = true,
643
faf919f1 644 .init = device_init,
034c6ed7 645 .done = device_done,
718db961
LP
646 .load = unit_load_fragment_and_dropin_optional,
647
f50e0a01
LP
648 .coldplug = device_coldplug,
649
5cb5a6ff
LP
650 .dump = device_dump,
651
f50e0a01 652 .active_state = device_active_state,
10a94420 653 .sub_state_to_string = device_sub_state_to_string,
25ac040b 654
c4e2ceae 655 .bus_interface = "org.freedesktop.systemd1.Device",
718db961 656 .bus_vtable = bus_device_vtable,
4139c1b2 657
a7f241db 658 .following = device_following,
6210e7fc 659 .following_set = device_following_set,
a7f241db 660
f50e0a01 661 .enumerate = device_enumerate,
c6918296
MS
662 .shutdown = device_shutdown,
663
664 .status_message_formats = {
665 .starting_stopping = {
666 [0] = "Expecting device %s...",
667 },
668 .finished_start_job = {
669 [JOB_DONE] = "Found device %s.",
670 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
671 },
672 },
5cb5a6ff 673};