]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/scope.c
man: reorder/add sections to systemd.exec(5) (#7412)
[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
2d4a39e7
LP
62 free(s->controller);
63
718db961
LP
64 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
65}
66
36c16a7c 67static int scope_arm_timer(Scope *s, usec_t usec) {
718db961
LP
68 int r;
69
70 assert(s);
71
718db961 72 if (s->timer_event_source) {
36c16a7c 73 r = sd_event_source_set_time(s->timer_event_source, usec);
718db961
LP
74 if (r < 0)
75 return r;
76
77 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
78 }
79
36c16a7c
LP
80 if (usec == USEC_INFINITY)
81 return 0;
82
cbf60d0a 83 r = sd_event_add_time(
6a0f1f6d
LP
84 UNIT(s)->manager->event,
85 &s->timer_event_source,
86 CLOCK_MONOTONIC,
36c16a7c 87 usec, 0,
6a0f1f6d 88 scope_dispatch_timer, s);
7dfbe2e3
TG
89 if (r < 0)
90 return r;
91
92 (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");
93
94 return 0;
6c12b52e
LP
95}
96
97static void scope_set_state(Scope *s, ScopeState state) {
98 ScopeState old_state;
99 assert(s);
100
101 old_state = s->state;
102 s->state = state;
103
a911bb9a 104 if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
718db961 105 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
6c12b52e 106
a911bb9a
LP
107 if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
108 unit_unwatch_all_pids(UNIT(s));
109
6c12b52e 110 if (state != old_state)
a911bb9a 111 log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
6c12b52e
LP
112
113 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
114}
115
116static int scope_add_default_dependencies(Scope *s) {
117 int r;
118
119 assert(s);
120
4c9ea260
LP
121 if (!UNIT(s)->default_dependencies)
122 return 0;
123
6c12b52e
LP
124 /* Make sure scopes are unloaded on shutdown */
125 r = unit_add_two_dependencies_by_name(
126 UNIT(s),
127 UNIT_BEFORE, UNIT_CONFLICTS,
eef85c4a
LP
128 SPECIAL_SHUTDOWN_TARGET, NULL, true,
129 UNIT_DEPENDENCY_DEFAULT);
6c12b52e
LP
130 if (r < 0)
131 return r;
132
133 return 0;
134}
135
136static int scope_verify(Scope *s) {
137 assert(s);
138
139 if (UNIT(s)->load_state != UNIT_LOADED)
140 return 0;
141
efdb0237 142 if (set_isempty(UNIT(s)->pids) &&
2c289ea8 143 !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
efdb0237 144 !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
f2341e0a 145 log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
6c12b52e
LP
146 return -EINVAL;
147 }
148
149 return 0;
150}
151
8e4e851f
LP
152static int scope_load_init_scope(Unit *u) {
153 assert(u);
154
155 if (!unit_has_name(u, SPECIAL_INIT_SCOPE))
156 return 0;
157
158 u->transient = true;
f5869324 159 u->perpetual = true;
8e4e851f
LP
160
161 /* init.scope is a bit special, as it has to stick around forever. Because of its special semantics we
162 * synthesize it here, instead of relying on the unit file on disk. */
163
164 u->default_dependencies = false;
165 u->ignore_on_isolate = true;
8e4e851f
LP
166
167 SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
168
169 /* Prettify things, if we can. */
170 if (!u->description)
171 u->description = strdup("System and Service Manager");
172 if (!u->documentation)
173 (void) strv_extend(&u->documentation, "man:systemd(1)");
174
175 return 1;
176}
177
6c12b52e
LP
178static int scope_load(Unit *u) {
179 Scope *s = SCOPE(u);
180 int r;
181
182 assert(s);
183 assert(u->load_state == UNIT_STUB);
184
2c289ea8 185 if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
4f4afc88 186 /* Refuse to load non-transient scope units, but allow them while reloading. */
6c12b52e
LP
187 return -ENOENT;
188
8e4e851f
LP
189 r = scope_load_init_scope(u);
190 if (r < 0)
191 return r;
4f4afc88 192 r = unit_load_fragment_and_dropin_optional(u);
6c12b52e
LP
193 if (r < 0)
194 return r;
195
4f4afc88
LP
196 if (u->load_state == UNIT_LOADED) {
197 r = unit_patch_contexts(u);
198 if (r < 0)
199 return r;
598459ce 200
4f4afc88
LP
201 r = unit_set_default_slice(u);
202 if (r < 0)
203 return r;
6c12b52e 204
4f4afc88
LP
205 r = scope_add_default_dependencies(s);
206 if (r < 0)
207 return r;
208 }
6c12b52e
LP
209
210 return scope_verify(s);
211}
212
be847e82 213static int scope_coldplug(Unit *u) {
6c12b52e
LP
214 Scope *s = SCOPE(u);
215 int r;
216
217 assert(s);
218 assert(s->state == SCOPE_DEAD);
219
36c16a7c
LP
220 if (s->deserialized_state == s->state)
221 return 0;
a911bb9a 222
36c16a7c
LP
223 if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
224 r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec));
225 if (r < 0)
226 return r;
6c12b52e
LP
227 }
228
36c16a7c
LP
229 if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
230 unit_watch_all_pids(UNIT(s));
231
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
2d4a39e7
LP
275 /* If we have a controller set let's ask the controller nicely
276 * to terminate the scope, instead of us going directly into
1d98fef1 277 * SIGTERM berserk mode */
2d4a39e7
LP
278 if (state == SCOPE_STOP_SIGTERM)
279 skip_signal = bus_scope_send_request_stop(s) > 0;
280
59ec09a8
ZJS
281 if (skip_signal)
282 r = 1; /* wait */
283 else {
2d4a39e7
LP
284 r = unit_kill_context(
285 UNIT(s),
286 &s->kill_context,
3862e809
LP
287 state != SCOPE_STOP_SIGTERM ? KILL_KILL :
288 s->was_abandoned ? KILL_TERMINATE_AND_LOG :
289 KILL_TERMINATE,
2d4a39e7
LP
290 -1, -1, false);
291 if (r < 0)
292 goto fail;
59ec09a8 293 }
6c12b52e
LP
294
295 if (r > 0) {
36c16a7c 296 r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
718db961
LP
297 if (r < 0)
298 goto fail;
6c12b52e
LP
299
300 scope_set_state(s, state);
ac84d1fb
LP
301 } else if (state == SCOPE_STOP_SIGTERM)
302 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
303 else
6c12b52e
LP
304 scope_enter_dead(s, SCOPE_SUCCESS);
305
306 return;
307
308fail:
f2341e0a 309 log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
6c12b52e
LP
310
311 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
312}
313
314static int scope_start(Unit *u) {
315 Scope *s = SCOPE(u);
316 int r;
317
318 assert(s);
319
efdb0237
LP
320 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
321 return -EPERM;
322
7b617155
LP
323 if (s->state == SCOPE_FAILED)
324 return -EPERM;
325
dd305ec9 326 /* We can't fulfill this right now, please try again later */
3742095b 327 if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
6c12b52e
LP
328 return -EAGAIN;
329
330 assert(s->state == SCOPE_DEAD);
331
2c289ea8 332 if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
6c12b52e
LP
333 return -ENOENT;
334
4b58153d
LP
335 r = unit_acquire_invocation_id(u);
336 if (r < 0)
337 return r;
338
5ad096b3 339 (void) unit_realize_cgroup(u);
906c06f6
DM
340 (void) unit_reset_cpu_accounting(u);
341 (void) unit_reset_ip_accounting(u);
5ad096b3 342
d3070fbd
LP
343 unit_export_state_files(UNIT(s));
344
7b3fd631 345 r = unit_attach_pids_to_cgroup(u);
dd305ec9 346 if (r < 0) {
f2341e0a 347 log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
68a01fb6 348 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
6c12b52e 349 return r;
dd305ec9 350 }
6c12b52e 351
6c12b52e
LP
352 s->result = SCOPE_SUCCESS;
353
354 scope_set_state(s, SCOPE_RUNNING);
82a2b6bb 355 return 1;
6c12b52e
LP
356}
357
358static int scope_stop(Unit *u) {
359 Scope *s = SCOPE(u);
360
361 assert(s);
6c12b52e 362
3742095b 363 if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
6c12b52e
LP
364 return 0;
365
3742095b 366 assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
6c12b52e
LP
367
368 scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
82a2b6bb 369 return 1;
6c12b52e
LP
370}
371
8bcca7e2
LP
372static void scope_reset_failed(Unit *u) {
373 Scope *s = SCOPE(u);
374
375 assert(s);
376
377 if (s->state == SCOPE_FAILED)
378 scope_set_state(s, SCOPE_DEAD);
379
380 s->result = SCOPE_SUCCESS;
381}
382
718db961 383static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
6c12b52e
LP
384 return unit_kill_common(u, who, signo, -1, -1, error);
385}
386
7a7821c8 387static int scope_get_timeout(Unit *u, usec_t *timeout) {
68db7a3b 388 Scope *s = SCOPE(u);
7a7821c8 389 usec_t t;
68db7a3b
ZJS
390 int r;
391
392 if (!s->timer_event_source)
393 return 0;
394
7a7821c8 395 r = sd_event_source_get_time(s->timer_event_source, &t);
68db7a3b
ZJS
396 if (r < 0)
397 return r;
7a7821c8
LP
398 if (t == USEC_INFINITY)
399 return 0;
68db7a3b 400
7a7821c8 401 *timeout = t;
68db7a3b
ZJS
402 return 1;
403}
404
6c12b52e
LP
405static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
406 Scope *s = SCOPE(u);
407
408 assert(s);
409 assert(f);
410 assert(fds);
411
412 unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
3862e809 413 unit_serialize_item(u, f, "was-abandoned", yes_no(s->was_abandoned));
6c12b52e
LP
414 return 0;
415}
416
417static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
418 Scope *s = SCOPE(u);
419
420 assert(u);
421 assert(key);
422 assert(value);
423 assert(fds);
424
425 if (streq(key, "state")) {
426 ScopeState state;
427
428 state = scope_state_from_string(value);
429 if (state < 0)
f2341e0a 430 log_unit_debug(u, "Failed to parse state value: %s", value);
6c12b52e
LP
431 else
432 s->deserialized_state = state;
433
3862e809
LP
434 } else if (streq(key, "was-abandoned")) {
435 int k;
436
437 k = parse_boolean(value);
438 if (k < 0)
439 log_unit_debug(u, "Failed to parse boolean value: %s", value);
440 else
441 s->was_abandoned = k;
6c12b52e 442 } else
f2341e0a 443 log_unit_debug(u, "Unknown serialization key: %s", key);
6c12b52e
LP
444
445 return 0;
446}
447
448static bool scope_check_gc(Unit *u) {
4e2744fc 449 assert(u);
6c12b52e
LP
450
451 /* Never clean up scopes that still have a process around,
452 * even if the scope is formally dead. */
453
700e2d63
LP
454 if (!u->cgroup_path)
455 return false;
4e2744fc 456
700e2d63 457 return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0;
6c12b52e
LP
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
472 /* If we get a SIGCHLD event for one of the processes we were
473 interested in, then we look for others to watch, under the
474 assumption that we'll sooner or later get a SIGCHLD for
475 them, as the original process we watched was probably the
476 parent of them, and they are hence now our children. */
477
478 unit_tidy_watch_pids(u, 0, 0);
479 unit_watch_all_pids(u);
480
bbc85a16
EV
481 /* If the PID set is empty now, then let's finish this off
482 (On unified we use proper notifications) */
c22800e4 483 if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) == 0 && set_isempty(u->pids))
a911bb9a
LP
484 scope_notify_cgroup_empty_event(u);
485}
486
718db961
LP
487static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
488 Scope *s = SCOPE(userdata);
6c12b52e
LP
489
490 assert(s);
718db961 491 assert(s->timer_event_source == source);
6c12b52e
LP
492
493 switch (s->state) {
494
495 case SCOPE_STOP_SIGTERM:
496 if (s->kill_context.send_sigkill) {
f2341e0a 497 log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
6c12b52e
LP
498 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
499 } else {
f2341e0a 500 log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
6c12b52e
LP
501 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
502 }
503
504 break;
505
506 case SCOPE_STOP_SIGKILL:
f2341e0a 507 log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
6c12b52e
LP
508 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
509 break;
510
511 default:
512 assert_not_reached("Timeout at wrong time.");
513 }
718db961
LP
514
515 return 0;
6c12b52e
LP
516}
517
a911bb9a
LP
518int scope_abandon(Scope *s) {
519 assert(s);
6c12b52e 520
efdb0237
LP
521 if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
522 return -EPERM;
523
a911bb9a
LP
524 if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
525 return -ESTALE;
6c12b52e 526
3862e809 527 s->was_abandoned = true;
a1e58e8e 528 s->controller = mfree(s->controller);
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
624 .check_gc = scope_check_gc,
625
a911bb9a
LP
626 .sigchld_event = scope_sigchld_event,
627
8bcca7e2
LP
628 .reset_failed = scope_reset_failed,
629
6c12b52e
LP
630 .notify_cgroup_empty = scope_notify_cgroup_empty_event,
631
718db961 632 .bus_vtable = bus_scope_vtable,
6c12b52e
LP
633 .bus_set_property = bus_scope_set_property,
634 .bus_commit_properties = bus_scope_commit_properties,
635
efdb0237 636 .enumerate = scope_enumerate,
6c12b52e 637};