]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/device.c
man: improve wording of systemctl's --after/--before
[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
965e5c5d
LP
186static int device_make_description(Unit *u, struct udev_device *dev, const char *path) {
187 const char *model;
188
189 assert(u);
190 assert(dev);
191 assert(path);
192
193 model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
194 if (!model)
195 model = udev_device_get_property_value(dev, "ID_MODEL");
196
197 if (model) {
198 const char *label;
199
200 /* Try to concatenate the device model string with a label, if there is one */
201 label = udev_device_get_property_value(dev, "ID_FS_LABEL");
202 if (!label)
203 label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
204 if (!label)
205 label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
206
207 if (label) {
208 _cleanup_free_ char *j;
209
210 j = strjoin(model, " ", label, NULL);
211 if (j)
212 return unit_set_description(u, j);
213 }
214
215 return unit_set_description(u, model);
216 }
217
218 return unit_set_description(u, path);
219}
220
221static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
222 const char *wants;
223 char *state, *w;
224 size_t l;
225 int r;
226
227 assert(u);
228 assert(dev);
229
230 wants = udev_device_get_property_value(
231 dev,
232 u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS");
233
234 if (!wants)
235 return 0;
236
237 FOREACH_WORD_QUOTED(w, l, wants, state) {
238 _cleanup_free_ char *n = NULL;
239 char e[l+1];
240
241 memcpy(e, w, l);
242 e[l] = 0;
243
244 n = unit_name_mangle(e, MANGLE_NOGLOB);
245 if (!n)
246 return -ENOMEM;
247
248 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
249 if (r < 0)
250 return r;
251 }
252
253 return 0;
254}
255
8fe914ec 256static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
965e5c5d 257 const char *sysfs;
25ac040b 258 Unit *u = NULL;
25ac040b 259 bool delete;
965e5c5d 260 int r;
25ac040b
LP
261
262 assert(m);
965e5c5d
LP
263 assert(dev);
264 assert(path);
25ac040b 265
b47d419c
ZJS
266 sysfs = udev_device_get_syspath(dev);
267 if (!sysfs)
f1421cc6 268 return 0;
7f275a9f 269
b47d419c
ZJS
270 r = device_find_escape_name(m, path, &u);
271 if (r < 0)
aab14b13 272 return r;
25ac040b 273
5845b46b 274 if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
8fe914ec 275 return -EEXIST;
25ac040b 276
aab14b13
LP
277 if (!u) {
278 delete = true;
279
7d17cfbc
MS
280 u = unit_new(m, sizeof(Device));
281 if (!u)
f1421cc6 282 return log_oom();
25ac040b 283
7d17cfbc
MS
284 r = device_add_escaped_name(u, path);
285 if (r < 0)
25ac040b
LP
286 goto fail;
287
ee6cb288
LP
288 unit_add_to_load_queue(u);
289 } else
290 delete = false;
291
292 /* If this was created via some dependency and has not
293 * actually been seen yet ->sysfs will not be
294 * initialized. Hence initialize it if necessary. */
295
296 if (!DEVICE(u)->sysfs) {
297 Device *first;
298
718db961
LP
299 DEVICE(u)->sysfs = strdup(sysfs);
300 if (!DEVICE(u)->sysfs) {
25ac040b
LP
301 r = -ENOMEM;
302 goto fail;
303 }
304
718db961
LP
305 r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func);
306 if (r < 0)
307 goto fail;
25ac040b 308
8fe914ec 309 first = hashmap_get(m->devices_by_sysfs, sysfs);
71fda00f 310 LIST_PREPEND(same_sysfs, first, DEVICE(u));
8fe914ec 311
b47d419c
ZJS
312 r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
313 if (r < 0)
25ac040b 314 goto fail;
ee6cb288 315 }
8fe914ec 316
965e5c5d 317 device_make_description(u, dev, path);
aab14b13 318
8fe914ec
LP
319 if (main) {
320 /* The additional systemd udev properties we only
321 * interpret for the main object */
25ac040b 322
965e5c5d
LP
323 r = device_add_udev_wants(u, dev);
324 if (r < 0)
325 goto fail;
a7f241db 326 }
f94ea366 327
f1421cc6
LP
328 /* Note that this won't dispatch the load queue, the caller
329 * has to do that if needed and appropriate */
330
c1e1601e 331 unit_add_to_dbus_queue(u);
25ac040b
LP
332 return 0;
333
334fail:
ee5f3479
LP
335 log_warning("Failed to load device unit: %s", strerror(-r));
336
25ac040b
LP
337 if (delete && u)
338 unit_free(u);
ee5f3479 339
25ac040b
LP
340 return r;
341}
342
f1421cc6
LP
343static int device_process_new_device(Manager *m, struct udev_device *dev) {
344 const char *sysfs, *dn, *alias;
8fe914ec 345 struct udev_list_entry *item = NULL, *first = NULL;
003ac9d0 346 int r;
8fe914ec
LP
347
348 assert(m);
349
718db961
LP
350 sysfs = udev_device_get_syspath(dev);
351 if (!sysfs)
f1421cc6 352 return 0;
8fe914ec
LP
353
354 /* Add the main unit named after the sysfs path */
003ac9d0
HH
355 r = device_update_unit(m, dev, sysfs, true);
356 if (r < 0)
357 return r;
8fe914ec
LP
358
359 /* Add an additional unit for the device node */
f1421cc6
LP
360 dn = udev_device_get_devnode(dev);
361 if (dn)
8fe914ec
LP
362 device_update_unit(m, dev, dn, false);
363
364 /* Add additional units for all symlinks */
365 first = udev_device_get_devlinks_list_entry(dev);
366 udev_list_entry_foreach(item, first) {
367 const char *p;
5845b46b 368 struct stat st;
8fe914ec
LP
369
370 /* Don't bother with the /dev/block links */
371 p = udev_list_entry_get_name(item);
372
373 if (path_startswith(p, "/dev/block/") ||
374 path_startswith(p, "/dev/char/"))
375 continue;
376
5845b46b
LP
377 /* Verify that the symlink in the FS actually belongs
378 * to this device. This is useful to deal with
379 * conflicting devices, e.g. when two disks want the
380 * same /dev/disk/by-label/xxx link because they have
381 * the same label. We want to make sure that the same
382 * device that won the symlink wins in systemd, so we
383 * check the device node major/minor*/
384 if (stat(p, &st) >= 0)
385 if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
386 st.st_rdev != udev_device_get_devnum(dev))
387 continue;
388
8fe914ec
LP
389 device_update_unit(m, dev, p, false);
390 }
391
f1421cc6
LP
392 /* Add additional units for all explicitly configured
393 * aliases */
394 alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
395 if (alias) {
396 char *state, *w;
397 size_t l;
8fe914ec 398
f1421cc6
LP
399 FOREACH_WORD_QUOTED(w, l, alias, state) {
400 char e[l+1];
8fe914ec 401
f1421cc6
LP
402 memcpy(e, w, l);
403 e[l] = 0;
404
405 if (path_is_absolute(e))
406 device_update_unit(m, dev, e, false);
407 else
408 log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
409 }
8fe914ec
LP
410 }
411
412 return 0;
413}
414
f1421cc6
LP
415static void device_set_path_plugged(Manager *m, struct udev_device *dev) {
416 const char *sysfs;
417 Device *d, *l;
25ac040b
LP
418
419 assert(m);
f1421cc6 420 assert(dev);
25ac040b 421
f1421cc6
LP
422 sysfs = udev_device_get_syspath(dev);
423 if (!sysfs)
424 return;
25ac040b 425
f1421cc6
LP
426 l = hashmap_get(m->devices_by_sysfs, sysfs);
427 LIST_FOREACH(same_sysfs, d, l)
428 device_set_state(d, DEVICE_PLUGGED);
25ac040b
LP
429}
430
f94ea366
LP
431static int device_process_removed_device(Manager *m, struct udev_device *dev) {
432 const char *sysfs;
f94ea366
LP
433 Device *d;
434
435 assert(m);
436 assert(dev);
437
f1421cc6
LP
438 sysfs = udev_device_get_syspath(dev);
439 if (!sysfs)
f94ea366
LP
440 return -ENOMEM;
441
8fe914ec
LP
442 /* Remove all units of this sysfs path */
443 while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
444 device_unset_sysfs(d);
445 device_set_state(d, DEVICE_DEAD);
446 }
f94ea366 447
f94ea366
LP
448 return 0;
449}
450
f1421cc6
LP
451static bool device_is_ready(struct udev_device *dev) {
452 const char *ready;
453
454 assert(dev);
455
456 ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
457 if (!ready)
458 return true;
459
460 return parse_boolean(ready) != 0;
461}
462
463static int device_process_new_path(Manager *m, const char *path) {
464 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
465
466 assert(m);
467 assert(path);
468
469 dev = udev_device_new_from_syspath(m->udev, path);
470 if (!dev)
471 return log_oom();
472
473 if (!device_is_ready(dev))
474 return 0;
475
476 return device_process_new_device(m, dev);
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
f1421cc6
LP
516 set = set_new(NULL, NULL);
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. */
571 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
LP
604 first = udev_enumerate_get_list_entry(e);
605 udev_list_entry_foreach(item, first)
f1421cc6 606 device_process_new_path(m, udev_list_entry_get_name(item));
25ac040b 607
25ac040b
LP
608 return 0;
609
610fail:
25ac040b
LP
611 device_shutdown(m);
612 return r;
5cb5a6ff
LP
613}
614
718db961
LP
615static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
616 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
718db961 617 Manager *m = userdata;
f1421cc6 618 const char *action;
718db961 619 int r;
f94ea366
LP
620
621 assert(m);
99448c1f 622
718db961 623 if (revents != EPOLLIN) {
99448c1f
KS
624 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
625
626 if (!ratelimit_test(&limit))
627 log_error("Failed to get udev event: %m");
718db961
LP
628 if (!(revents & EPOLLIN))
629 return 0;
99448c1f 630 }
f94ea366 631
718db961
LP
632 /*
633 * libudev might filter-out devices which pass the bloom
634 * filter, so getting NULL here is not necessarily an error.
635 */
636 dev = udev_monitor_receive_device(m->udev_monitor);
637 if (!dev)
638 return 0;
f94ea366 639
718db961
LP
640 action = udev_device_get_action(dev);
641 if (!action) {
f94ea366 642 log_error("Failed to get udev action string.");
718db961 643 return 0;
f94ea366
LP
644 }
645
f1421cc6 646 if (streq(action, "remove") || !device_is_ready(dev)) {
718db961
LP
647 r = device_process_removed_device(m, dev);
648 if (r < 0)
f1421cc6 649 log_error("Failed to process device remove event: %s", strerror(-r));
9670d583
LP
650
651 r = swap_process_removed_device(m, dev);
652 if (r < 0)
653 log_error("Failed to process swap device remove event: %s", strerror(-r));
654
f94ea366 655 } else {
f1421cc6 656 r = device_process_new_device(m, dev);
718db961 657 if (r < 0)
f1421cc6
LP
658 log_error("Failed to process device new event: %s", strerror(-r));
659
9670d583
LP
660 r = swap_process_new_device(m, dev);
661 if (r < 0)
662 log_error("Failed to process swap device new event: %s", strerror(-r));
663
f1421cc6
LP
664 manager_dispatch_load_queue(m);
665
666 device_set_path_plugged(m, dev);
f94ea366
LP
667 }
668
718db961 669 return 0;
f94ea366
LP
670}
671
a16e1123
LP
672static const char* const device_state_table[_DEVICE_STATE_MAX] = {
673 [DEVICE_DEAD] = "dead",
73608ed9 674 [DEVICE_PLUGGED] = "plugged"
a16e1123
LP
675};
676
677DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
678
87f0e418 679const UnitVTable device_vtable = {
7d17cfbc 680 .object_size = sizeof(Device),
f975e971
LP
681 .sections =
682 "Unit\0"
683 "Device\0"
684 "Install\0",
5cb5a6ff 685
9e2f7c11
LP
686 .no_instances = true,
687
faf919f1 688 .init = device_init,
034c6ed7 689 .done = device_done,
718db961
LP
690 .load = unit_load_fragment_and_dropin_optional,
691
f50e0a01
LP
692 .coldplug = device_coldplug,
693
5cb5a6ff
LP
694 .dump = device_dump,
695
f50e0a01 696 .active_state = device_active_state,
10a94420 697 .sub_state_to_string = device_sub_state_to_string,
25ac040b 698
c4e2ceae 699 .bus_interface = "org.freedesktop.systemd1.Device",
718db961 700 .bus_vtable = bus_device_vtable,
4139c1b2 701
a7f241db 702 .following = device_following,
6210e7fc 703 .following_set = device_following_set,
a7f241db 704
f50e0a01 705 .enumerate = device_enumerate,
c6918296
MS
706 .shutdown = device_shutdown,
707
708 .status_message_formats = {
709 .starting_stopping = {
710 [0] = "Expecting device %s...",
711 },
712 .finished_start_job = {
713 [JOB_DONE] = "Found device %s.",
714 [JOB_TIMEOUT] = "Timed out waiting for device %s.",
715 },
716 },
5cb5a6ff 717};