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