]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/scope.c
Merge pull request #8143 from yuwata/drop-unused-func
[thirdparty/systemd.git] / src / core / scope.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6c12b52e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
6c12b52e
LP
22#include <unistd.h>
23
b5efdb8a 24#include "alloc-util.h"
07630cea
LP
25#include "dbus-scope.h"
26#include "load-dropin.h"
6c12b52e 27#include "log.h"
b5efdb8a 28#include "scope.h"
6c12b52e 29#include "special.h"
8b43440b 30#include "string-table.h"
07630cea
LP
31#include "string-util.h"
32#include "strv.h"
6c12b52e 33#include "unit-name.h"
efdb0237 34#include "unit.h"
6c12b52e
LP
35
36static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
37 [SCOPE_DEAD] = UNIT_INACTIVE,
38 [SCOPE_RUNNING] = UNIT_ACTIVE,
a911bb9a 39 [SCOPE_ABANDONED] = UNIT_ACTIVE,
6c12b52e
LP
40 [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
41 [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
42 [SCOPE_FAILED] = UNIT_FAILED
43};
44
718db961
LP
45static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
46
6c12b52e
LP
47static void scope_init(Unit *u) {
48 Scope *s = SCOPE(u);
49
50 assert(u);
51 assert(u->load_state == UNIT_STUB);
52
1f19a534 53 s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
1b4cd0cf 54 u->ignore_on_isolate = true;
6c12b52e
LP
55}
56
57static void scope_done(Unit *u) {
58 Scope *s = SCOPE(u);
59
60 assert(u);
61
371c0b79
LP
62 s->controller = mfree(s->controller);
63 s->controller_track = sd_bus_track_unref(s->controller_track);
2d4a39e7 64
718db961
LP
65 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
66}
67
36c16a7c 68static int scope_arm_timer(Scope *s, usec_t usec) {
718db961
LP
69 int r;
70
71 assert(s);
72
718db961 73 if (s->timer_event_source) {
36c16a7c 74 r = sd_event_source_set_time(s->timer_event_source, usec);
718db961
LP
75 if (r < 0)
76 return r;
77
78 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
79 }
80
36c16a7c
LP
81 if (usec == USEC_INFINITY)
82 return 0;
83
cbf60d0a 84 r = sd_event_add_time(
6a0f1f6d
LP
85 UNIT(s)->manager->event,
86 &s->timer_event_source,
87 CLOCK_MONOTONIC,
36c16a7c 88 usec, 0,
6a0f1f6d 89 scope_dispatch_timer, s);
7dfbe2e3
TG
90 if (r < 0)
91 return r;
92
93 (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");
94
95 return 0;
6c12b52e
LP
96}
97
98static void scope_set_state(Scope *s, ScopeState state) {
99 ScopeState old_state;
100 assert(s);
101
102 old_state = s->state;
103 s->state = state;
104
a911bb9a 105 if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
718db961 106 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
6c12b52e 107
a911bb9a
LP
108 if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
109 unit_unwatch_all_pids(UNIT(s));
110
6c12b52e 111 if (state != old_state)
a911bb9a 112 log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
6c12b52e
LP
113
114 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
115}
116
117static int scope_add_default_dependencies(Scope *s) {
118 int r;
119
120 assert(s);
121
4c9ea260
LP
122 if (!UNIT(s)->default_dependencies)
123 return 0;
124
6c12b52e
LP
125 /* Make sure scopes are unloaded on shutdown */
126 r = unit_add_two_dependencies_by_name(
127 UNIT(s),
128 UNIT_BEFORE, UNIT_CONFLICTS,
eef85c4a
LP
129 SPECIAL_SHUTDOWN_TARGET, NULL, true,
130 UNIT_DEPENDENCY_DEFAULT);
6c12b52e
LP
131 if (r < 0)
132 return r;
133
134 return 0;
135}
136
137static int scope_verify(Scope *s) {
138 assert(s);
139
140 if (UNIT(s)->load_state != UNIT_LOADED)
141 return 0;
142
efdb0237 143 if (set_isempty(UNIT(s)->pids) &&
2c289ea8 144 !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
efdb0237 145 !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
f2341e0a 146 log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
6c12b52e
LP
147 return -EINVAL;
148 }
149
150 return 0;
151}
152
8e4e851f
LP
153static int scope_load_init_scope(Unit *u) {
154 assert(u);
155
156 if (!unit_has_name(u, SPECIAL_INIT_SCOPE))
157 return 0;
158
159 u->transient = true;
f5869324 160 u->perpetual = true;
8e4e851f
LP
161
162 /* init.scope is a bit special, as it has to stick around forever. Because of its special semantics we
163 * synthesize it here, instead of relying on the unit file on disk. */
164
165 u->default_dependencies = false;
8e4e851f
LP
166
167 /* Prettify things, if we can. */
168 if (!u->description)
169 u->description = strdup("System and Service Manager");
170 if (!u->documentation)
171 (void) strv_extend(&u->documentation, "man:systemd(1)");
172
173 return 1;
174}
175
6c12b52e
LP
176static int scope_load(Unit *u) {
177 Scope *s = SCOPE(u);
178 int r;
179
180 assert(s);
181 assert(u->load_state == UNIT_STUB);
182
2c289ea8 183 if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
4f4afc88 184 /* Refuse to load non-transient scope units, but allow them while reloading. */
6c12b52e
LP
185 return -ENOENT;
186
8e4e851f
LP
187 r = scope_load_init_scope(u);
188 if (r < 0)
189 return r;
4f4afc88 190 r = unit_load_fragment_and_dropin_optional(u);
6c12b52e
LP
191 if (r < 0)
192 return r;
193
4f4afc88
LP
194 if (u->load_state == UNIT_LOADED) {
195 r = unit_patch_contexts(u);
196 if (r < 0)
197 return r;
598459ce 198
4f4afc88
LP
199 r = unit_set_default_slice(u);
200 if (r < 0)
201 return r;
6c12b52e 202
4f4afc88
LP
203 r = scope_add_default_dependencies(s);
204 if (r < 0)
205 return r;
206 }
6c12b52e
LP
207
208 return scope_verify(s);
209}
210
be847e82 211static int scope_coldplug(Unit *u) {
6c12b52e
LP
212 Scope *s = SCOPE(u);
213 int r;
214
215 assert(s);
216 assert(s->state == SCOPE_DEAD);
217
36c16a7c
LP
218 if (s->deserialized_state == s->state)
219 return 0;
a911bb9a 220
36c16a7c
LP
221 if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
222 r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec));
223 if (r < 0)
224 return r;
6c12b52e
LP
225 }
226
36c16a7c
LP
227 if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
228 unit_watch_all_pids(UNIT(s));
229
371c0b79
LP
230 bus_scope_track_controller(s);
231
36c16a7c 232 scope_set_state(s, s->deserialized_state);
6c12b52e
LP
233 return 0;
234}
235
236static void scope_dump(Unit *u, FILE *f, const char *prefix) {
237 Scope *s = SCOPE(u);
238
239 assert(s);
240 assert(f);
241
242 fprintf(f,
243 "%sScope State: %s\n"
244 "%sResult: %s\n",
245 prefix, scope_state_to_string(s->state),
246 prefix, scope_result_to_string(s->result));
247
248 cgroup_context_dump(&s->cgroup_context, f, prefix);
249 kill_context_dump(&s->kill_context, f, prefix);
250}
251
252static void scope_enter_dead(Scope *s, ScopeResult f) {
253 assert(s);
254
a0fef983 255 if (s->result == SCOPE_SUCCESS)
6c12b52e
LP
256 s->result = f;
257
ed77d407
LP
258 if (s->result != SCOPE_SUCCESS)
259 log_unit_warning(UNIT(s), "Failed with result '%s'.", scope_result_to_string(s->result));
260
6c12b52e
LP
261 scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
262}
263
264static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
2d4a39e7 265 bool skip_signal = false;
6c12b52e
LP
266 int r;
267
268 assert(s);
269
a0fef983 270 if (s->result == SCOPE_SUCCESS)
6c12b52e
LP
271 s->result = f;
272
a911bb9a
LP
273 unit_watch_all_pids(UNIT(s));
274
371c0b79
LP
275 /* If we have a controller set let's ask the controller nicely to terminate the scope, instead of us going
276 * directly into SIGTERM berserk mode */
2d4a39e7
LP
277 if (state == SCOPE_STOP_SIGTERM)
278 skip_signal = bus_scope_send_request_stop(s) > 0;
279
59ec09a8
ZJS
280 if (skip_signal)
281 r = 1; /* wait */
282 else {
2d4a39e7
LP
283 r = unit_kill_context(
284 UNIT(s),
285 &s->kill_context,
3862e809
LP
286 state != SCOPE_STOP_SIGTERM ? KILL_KILL :
287 s->was_abandoned ? KILL_TERMINATE_AND_LOG :
288 KILL_TERMINATE,
2d4a39e7
LP
289 -1, -1, false);
290 if (r < 0)
291 goto fail;
59ec09a8 292 }
6c12b52e
LP
293
294 if (r > 0) {
36c16a7c 295 r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
718db961
LP
296 if (r < 0)
297 goto fail;
6c12b52e
LP
298
299 scope_set_state(s, state);
ac84d1fb
LP
300 } else if (state == SCOPE_STOP_SIGTERM)
301 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
302 else
6c12b52e
LP
303 scope_enter_dead(s, SCOPE_SUCCESS);
304
305 return;
306
307fail:
f2341e0a 308 log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
6c12b52e
LP
309
310 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
311}
312
313static int scope_start(Unit *u) {
314 Scope *s = SCOPE(u);
315 int r;
316
317 assert(s);
318
efdb0237
LP
319 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
320 return -EPERM;
321
7b617155
LP
322 if (s->state == SCOPE_FAILED)
323 return -EPERM;
324
dd305ec9 325 /* We can't fulfill this right now, please try again later */
3742095b 326 if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
6c12b52e
LP
327 return -EAGAIN;
328
329 assert(s->state == SCOPE_DEAD);
330
2c289ea8 331 if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
6c12b52e
LP
332 return -ENOENT;
333
371c0b79
LP
334 (void) bus_scope_track_controller(s);
335
4b58153d
LP
336 r = unit_acquire_invocation_id(u);
337 if (r < 0)
338 return r;
339
5ad096b3 340 (void) unit_realize_cgroup(u);
906c06f6
DM
341 (void) unit_reset_cpu_accounting(u);
342 (void) unit_reset_ip_accounting(u);
5ad096b3 343
d3070fbd
LP
344 unit_export_state_files(UNIT(s));
345
7b3fd631 346 r = unit_attach_pids_to_cgroup(u);
dd305ec9 347 if (r < 0) {
f2341e0a 348 log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
68a01fb6 349 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
6c12b52e 350 return r;
dd305ec9 351 }
6c12b52e 352
6c12b52e
LP
353 s->result = SCOPE_SUCCESS;
354
355 scope_set_state(s, SCOPE_RUNNING);
82a2b6bb 356 return 1;
6c12b52e
LP
357}
358
359static int scope_stop(Unit *u) {
360 Scope *s = SCOPE(u);
361
362 assert(s);
6c12b52e 363
3742095b 364 if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
6c12b52e
LP
365 return 0;
366
3742095b 367 assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
6c12b52e
LP
368
369 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
82a2b6bb 370 return 1;
6c12b52e
LP
371}
372
8bcca7e2
LP
373static void scope_reset_failed(Unit *u) {
374 Scope *s = SCOPE(u);
375
376 assert(s);
377
378 if (s->state == SCOPE_FAILED)
379 scope_set_state(s, SCOPE_DEAD);
380
381 s->result = SCOPE_SUCCESS;
382}
383
718db961 384static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
6c12b52e
LP
385 return unit_kill_common(u, who, signo, -1, -1, error);
386}
387
7a7821c8 388static int scope_get_timeout(Unit *u, usec_t *timeout) {
68db7a3b 389 Scope *s = SCOPE(u);
7a7821c8 390 usec_t t;
68db7a3b
ZJS
391 int r;
392
393 if (!s->timer_event_source)
394 return 0;
395
7a7821c8 396 r = sd_event_source_get_time(s->timer_event_source, &t);
68db7a3b
ZJS
397 if (r < 0)
398 return r;
7a7821c8
LP
399 if (t == USEC_INFINITY)
400 return 0;
68db7a3b 401
7a7821c8 402 *timeout = t;
68db7a3b
ZJS
403 return 1;
404}
405
6c12b52e
LP
406static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
407 Scope *s = SCOPE(u);
408
409 assert(s);
410 assert(f);
411 assert(fds);
412
413 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
3862e809 414 unit_serialize_item(u, f, "was-abandoned", yes_no(s->was_abandoned));
33fe0afe
LP
415
416 if (s->controller)
417 unit_serialize_item(u, f, "controller", s->controller);
418
6c12b52e
LP
419 return 0;
420}
421
422static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
423 Scope *s = SCOPE(u);
33fe0afe 424 int r;
6c12b52e
LP
425
426 assert(u);
427 assert(key);
428 assert(value);
429 assert(fds);
430
431 if (streq(key, "state")) {
432 ScopeState state;
433
434 state = scope_state_from_string(value);
435 if (state < 0)
f2341e0a 436 log_unit_debug(u, "Failed to parse state value: %s", value);
6c12b52e
LP
437 else
438 s->deserialized_state = state;
439
3862e809
LP
440 } else if (streq(key, "was-abandoned")) {
441 int k;
442
443 k = parse_boolean(value);
444 if (k < 0)
445 log_unit_debug(u, "Failed to parse boolean value: %s", value);
446 else
447 s->was_abandoned = k;
33fe0afe
LP
448 } else if (streq(key, "controller")) {
449
450 r = free_and_strdup(&s->controller, value);
451 if (r < 0)
452 log_oom();
453
6c12b52e 454 } else
f2341e0a 455 log_unit_debug(u, "Unknown serialization key: %s", key);
6c12b52e
LP
456
457 return 0;
458}
459
a911bb9a
LP
460static void scope_notify_cgroup_empty_event(Unit *u) {
461 Scope *s = SCOPE(u);
462 assert(u);
463
f2341e0a 464 log_unit_debug(u, "cgroup is empty");
a911bb9a
LP
465
466 if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
467 scope_enter_dead(s, SCOPE_SUCCESS);
468}
469
470static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
471
11aef522 472 assert(u);
a911bb9a 473
11aef522
LP
474 /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to
475 * watch, under the assumption that we'll sooner or later get a SIGCHLD for them, as the original
476 * process we watched was probably the parent of them, and they are hence now our children. */
a911bb9a
LP
477 unit_tidy_watch_pids(u, 0, 0);
478 unit_watch_all_pids(u);
479
11aef522
LP
480 /* If the PID set is empty now, then let's finish this off. */
481 unit_synthesize_cgroup_empty_event(u);
a911bb9a
LP
482}
483
718db961
LP
484static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
485 Scope *s = SCOPE(userdata);
6c12b52e
LP
486
487 assert(s);
718db961 488 assert(s->timer_event_source == source);
6c12b52e
LP
489
490 switch (s->state) {
491
492 case SCOPE_STOP_SIGTERM:
493 if (s->kill_context.send_sigkill) {
f2341e0a 494 log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
6c12b52e
LP
495 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
496 } else {
f2341e0a 497 log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
6c12b52e
LP
498 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
499 }
500
501 break;
502
503 case SCOPE_STOP_SIGKILL:
f2341e0a 504 log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
6c12b52e
LP
505 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
506 break;
507
508 default:
509 assert_not_reached("Timeout at wrong time.");
510 }
718db961
LP
511
512 return 0;
6c12b52e
LP
513}
514
a911bb9a
LP
515int scope_abandon(Scope *s) {
516 assert(s);
6c12b52e 517
efdb0237
LP
518 if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
519 return -EPERM;
520
a911bb9a
LP
521 if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
522 return -ESTALE;
6c12b52e 523
3862e809 524 s->was_abandoned = true;
371c0b79 525
a1e58e8e 526 s->controller = mfree(s->controller);
371c0b79
LP
527 s->controller_track = sd_bus_track_unref(s->controller_track);
528
8cb83266 529 scope_set_state(s, SCOPE_ABANDONED);
6c12b52e 530
a911bb9a
LP
531 /* The client is no longer watching the remaining processes,
532 * so let's step in here, under the assumption that the
533 * remaining processes will be sooner or later reassigned to
534 * us as parent. */
6c12b52e 535
a911bb9a
LP
536 unit_tidy_watch_pids(UNIT(s), 0, 0);
537 unit_watch_all_pids(UNIT(s));
6c12b52e 538
a911bb9a 539 return 0;
6c12b52e
LP
540}
541
542_pure_ static UnitActiveState scope_active_state(Unit *u) {
543 assert(u);
544
545 return state_translation_table[SCOPE(u)->state];
546}
547
548_pure_ static const char *scope_sub_state_to_string(Unit *u) {
549 assert(u);
550
551 return scope_state_to_string(SCOPE(u)->state);
552}
553
ba64af90 554static void scope_enumerate(Manager *m) {
efdb0237
LP
555 Unit *u;
556 int r;
557
558 assert(m);
559
560 /* Let's unconditionally add the "init.scope" special unit
561 * that encapsulates PID 1. Note that PID 1 already is in the
562 * cgroup for this, we hence just need to allocate the object
563 * for it and that's it. */
564
565 u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
566 if (!u) {
a581e45a 567 r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
efdb0237 568 if (r < 0) {
a581e45a 569 log_error_errno(r, "Failed to allocate the special " SPECIAL_INIT_SCOPE " unit: %m");
ba64af90 570 return;
efdb0237
LP
571 }
572 }
573
574 u->transient = true;
f5869324 575 u->perpetual = true;
efdb0237 576 SCOPE(u)->deserialized_state = SCOPE_RUNNING;
efdb0237
LP
577
578 unit_add_to_load_queue(u);
579 unit_add_to_dbus_queue(u);
efdb0237
LP
580}
581
6c12b52e
LP
582static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
583 [SCOPE_SUCCESS] = "success",
584 [SCOPE_FAILURE_RESOURCES] = "resources",
585 [SCOPE_FAILURE_TIMEOUT] = "timeout",
586};
587
588DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
589
590const UnitVTable scope_vtable = {
591 .object_size = sizeof(Scope),
718db961
LP
592 .cgroup_context_offset = offsetof(Scope, cgroup_context),
593 .kill_context_offset = offsetof(Scope, kill_context),
594
6c12b52e
LP
595 .sections =
596 "Unit\0"
597 "Scope\0"
598 "Install\0",
6c12b52e 599 .private_section = "Scope",
6c12b52e 600
700e2d63 601 .can_transient = true,
6c12b52e
LP
602
603 .init = scope_init,
604 .load = scope_load,
605 .done = scope_done,
606
607 .coldplug = scope_coldplug,
608
609 .dump = scope_dump,
610
611 .start = scope_start,
612 .stop = scope_stop,
613
614 .kill = scope_kill,
615
68db7a3b
ZJS
616 .get_timeout = scope_get_timeout,
617
6c12b52e
LP
618 .serialize = scope_serialize,
619 .deserialize_item = scope_deserialize_item,
620
621 .active_state = scope_active_state,
622 .sub_state_to_string = scope_sub_state_to_string,
623
a911bb9a
LP
624 .sigchld_event = scope_sigchld_event,
625
8bcca7e2
LP
626 .reset_failed = scope_reset_failed,
627
6c12b52e
LP
628 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
629
718db961 630 .bus_vtable = bus_scope_vtable,
6c12b52e
LP
631 .bus_set_property = bus_scope_set_property,
632 .bus_commit_properties = bus_scope_commit_properties,
633
efdb0237 634 .enumerate = scope_enumerate,
6c12b52e 635};