• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15746219612

18 Jun 2025 03:36PM UTC coverage: 72.045% (-0.04%) from 72.087%
15746219612

push

github

bluca
test-cpu-set-util: use ASSERT_XYZ() macros

119 of 121 new or added lines in 1 file covered. (98.35%)

1096 existing lines in 62 files now uncovered.

300222 of 416715 relevant lines covered (72.04%)

712541.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.5
/src/core/scope.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "sd-bus.h"
6

7
#include "cgroup-setup.h"
8
#include "dbus-scope.h"
9
#include "dbus-unit.h"
10
#include "exit-status.h"
11
#include "log.h"
12
#include "manager.h"
13
#include "parse-util.h"
14
#include "pidref.h"
15
#include "random-util.h"
16
#include "scope.h"
17
#include "serialize.h"
18
#include "set.h"
19
#include "special.h"
20
#include "string-table.h"
21
#include "string-util.h"
22
#include "strv.h"
23
#include "unit.h"
24
#include "user-util.h"
25

26
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
27
        [SCOPE_DEAD]         = UNIT_INACTIVE,
28
        [SCOPE_START_CHOWN]  = UNIT_ACTIVATING,
29
        [SCOPE_RUNNING]      = UNIT_ACTIVE,
30
        [SCOPE_ABANDONED]    = UNIT_ACTIVE,
31
        [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
32
        [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
33
        [SCOPE_FAILED]       = UNIT_FAILED,
34
};
35

36
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
37

38
static void scope_init(Unit *u) {
340✔
39
        Scope *s = ASSERT_PTR(SCOPE(u));
340✔
40

41
        assert(u->load_state == UNIT_STUB);
340✔
42

43
        s->runtime_max_usec = USEC_INFINITY;
340✔
44
        s->timeout_stop_usec = u->manager->defaults.timeout_stop_usec;
340✔
45
        u->ignore_on_isolate = true;
340✔
46
        s->user = s->group = NULL;
340✔
47
        s->oom_policy = _OOM_POLICY_INVALID;
340✔
48
}
340✔
49

50
static void scope_done(Unit *u) {
340✔
51
        Scope *s = ASSERT_PTR(SCOPE(u));
340✔
52

53
        s->controller = mfree(s->controller);
340✔
54
        s->controller_track = sd_bus_track_unref(s->controller_track);
340✔
55

56
        s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
340✔
57

58
        s->user = mfree(s->user);
340✔
59
        s->group = mfree(s->group);
340✔
60
}
340✔
61

62
static usec_t scope_running_timeout(Scope *s) {
329✔
63
        usec_t delta = 0;
329✔
64

65
        assert(s);
329✔
66

67
        if (s->runtime_rand_extra_usec != 0) {
329✔
68
                delta = random_u64_range(s->runtime_rand_extra_usec);
×
69
                log_unit_debug(UNIT(s), "Adding delta of %s sec to timeout", FORMAT_TIMESPAN(delta, USEC_PER_SEC));
×
70
        }
71

72
        return usec_add(usec_add(UNIT(s)->active_enter_timestamp.monotonic,
329✔
73
                                 s->runtime_max_usec),
74
                        delta);
75
}
76

77
static int scope_arm_timer(Scope *s, bool relative, usec_t usec) {
329✔
78
        assert(s);
329✔
79

80
        return unit_arm_timer(UNIT(s), &s->timer_event_source, relative, usec, scope_dispatch_timer);
329✔
81
}
82

83
static void scope_set_state(Scope *s, ScopeState state) {
342✔
84
        ScopeState old_state;
342✔
85

86
        assert(s);
342✔
87

88
        if (s->state != state)
342✔
89
                bus_unit_send_pending_change_signal(UNIT(s), false);
342✔
90

91
        old_state = s->state;
342✔
92
        s->state = state;
342✔
93

94
        if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN, SCOPE_RUNNING))
342✔
95
                s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
13✔
96

97
        if (!IN_SET(old_state, SCOPE_DEAD, SCOPE_FAILED) && IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
342✔
98
                unit_unwatch_all_pids(UNIT(s));
8✔
99

100
        if (state != old_state)
342✔
101
                log_unit_debug(UNIT(s), "Changed %s -> %s",
342✔
102
                               scope_state_to_string(old_state), scope_state_to_string(state));
103

104
        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
342✔
105
}
342✔
106

107
static int scope_add_default_dependencies(Scope *s) {
330✔
108
        int r;
330✔
109

110
        assert(s);
330✔
111

112
        if (!UNIT(s)->default_dependencies)
330✔
113
                return 0;
114

115
        /* Make sure scopes are unloaded on shutdown */
116
        r = unit_add_two_dependencies_by_name(
168✔
117
                        UNIT(s),
56✔
118
                        UNIT_BEFORE, UNIT_CONFLICTS,
119
                        SPECIAL_SHUTDOWN_TARGET, true,
120
                        UNIT_DEPENDENCY_DEFAULT);
121
        if (r < 0)
56✔
122
                return r;
×
123

124
        return 0;
125
}
126

127
static int scope_verify(Scope *s) {
330✔
128
        assert(s);
330✔
129
        assert(UNIT(s)->load_state == UNIT_LOADED);
330✔
130

131
        if (set_isempty(UNIT(s)->pids) &&
330✔
132
            !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
531✔
133
            !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
217✔
134
                return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT), "Scope has no PIDs. Refusing.");
×
135

136
        return 0;
137
}
138

139
static int scope_load_init_scope(Unit *u) {
330✔
140
        assert(u);
330✔
141

142
        if (!unit_has_name(u, SPECIAL_INIT_SCOPE))
330✔
143
                return 0;
144

145
        u->transient = true;
274✔
146
        u->perpetual = true;
274✔
147

148
        /* init.scope is a bit special, as it has to stick around forever. Because of its special semantics we
149
         * synthesize it here, instead of relying on the unit file on disk. */
150

151
        u->default_dependencies = false;
274✔
152

153
        /* Prettify things, if we can. */
154
        if (!u->description)
274✔
155
                u->description = strdup("System and Service Manager");
274✔
156
        if (!u->documentation)
274✔
157
                (void) strv_extend(&u->documentation, "man:systemd(1)");
274✔
158

159
        return 1;
160
}
161

162
static int scope_add_extras(Scope *s) {
330✔
163
        int r;
330✔
164

165
        r = unit_patch_contexts(UNIT(s));
330✔
166
        if (r < 0)
330✔
167
                return r;
168

169
        r = unit_set_default_slice(UNIT(s));
330✔
170
        if (r < 0)
330✔
171
                return r;
172

173
        if (s->oom_policy < 0)
330✔
174
                s->oom_policy = s->cgroup_context.delegate ? OOM_CONTINUE : UNIT(s)->manager->defaults.oom_policy;
277✔
175

176
        s->cgroup_context.memory_oom_group = s->oom_policy == OOM_KILL;
330✔
177

178
        return scope_add_default_dependencies(s);
330✔
179
}
180

181
static int scope_load(Unit *u) {
356✔
182
        Scope *s = ASSERT_PTR(SCOPE(u));
356✔
183
        int r;
356✔
184

185
        assert(u->load_state == UNIT_STUB);
356✔
186

187
        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
356✔
188
                /* Refuse to load non-transient scope units, but allow them while reloading. */
189
                return -ENOENT;
190

191
        r = scope_load_init_scope(u);
330✔
192
        if (r < 0)
330✔
193
                return r;
194

195
        r = unit_load_fragment_and_dropin(u, false);
330✔
196
        if (r < 0)
330✔
197
                return r;
198

199
        if (u->load_state != UNIT_LOADED)
330✔
200
                return 0;
201

202
        r = scope_add_extras(s);
330✔
203
        if (r < 0)
330✔
204
                return r;
205

206
        return scope_verify(s);
330✔
207
}
208

209
static usec_t scope_coldplug_timeout(Scope *s) {
313✔
210
        assert(s);
313✔
211

212
        switch (s->deserialized_state) {
313✔
213

214
        case SCOPE_RUNNING:
313✔
215
                return scope_running_timeout(s);
313✔
216

217
        case SCOPE_STOP_SIGKILL:
218
        case SCOPE_STOP_SIGTERM:
219
                return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
×
220

221
        default:
222
                return USEC_INFINITY;
223
        }
224
}
225

226
static int scope_coldplug(Unit *u) {
314✔
227
        Scope *s = ASSERT_PTR(SCOPE(u));
314✔
228
        int r;
314✔
229

230
        assert(s->state == SCOPE_DEAD);
314✔
231

232
        if (s->deserialized_state == s->state)
314✔
233
                return 0;
234

235
        r = scope_arm_timer(s, /* relative= */ false, scope_coldplug_timeout(s));
313✔
236
        if (r < 0)
313✔
237
                return r;
238

239
        if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED) && u->pids) {
313✔
240
                PidRef *pid;
×
241
                SET_FOREACH(pid, u->pids) {
×
242
                        r = unit_watch_pidref(u, pid, /* exclusive= */ false);
×
243
                        if (r < 0)
×
244
                                return r;
×
245
                }
246
        }
247

248
        bus_scope_track_controller(s);
313✔
249

250
        scope_set_state(s, s->deserialized_state);
313✔
251
        return 0;
313✔
252
}
253

254
static void scope_dump(Unit *u, FILE *f, const char *prefix) {
6✔
255
        Scope *s = ASSERT_PTR(SCOPE(u));
6✔
256

257
        assert(f);
6✔
258
        assert(prefix);
6✔
259

260
        fprintf(f,
12✔
261
                "%sScope State: %s\n"
262
                "%sResult: %s\n"
263
                "%sRuntimeMaxSec: %s\n"
264
                "%sRuntimeRandomizedExtraSec: %s\n"
265
                "%sOOMPolicy: %s\n",
266
                prefix, scope_state_to_string(s->state),
267
                prefix, scope_result_to_string(s->result),
268
                prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
6✔
269
                prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
6✔
270
                prefix, oom_policy_to_string(s->oom_policy));
271

272
        cgroup_context_dump(u, f, prefix);
6✔
273
        kill_context_dump(&s->kill_context, f, prefix);
6✔
274
}
6✔
275

276
static void scope_enter_dead(Scope *s, ScopeResult f) {
8✔
277
        assert(s);
8✔
278

279
        if (s->result == SCOPE_SUCCESS)
8✔
280
                s->result = f;
8✔
281

282
        unit_log_result(UNIT(s), s->result == SCOPE_SUCCESS, scope_result_to_string(s->result));
8✔
283
        scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
16✔
284
}
8✔
285

286
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
×
287
        bool skip_signal = false;
×
288
        int r;
×
289

290
        assert(s);
×
291

292
        if (s->result == SCOPE_SUCCESS)
×
293
                s->result = f;
×
294

295
        /* If we have a controller set let's ask the controller nicely to terminate the scope, instead of us going
296
         * directly into SIGTERM berserk mode */
297
        if (state == SCOPE_STOP_SIGTERM)
×
298
                skip_signal = bus_scope_send_request_stop(s) > 0;
×
299

300
        if (skip_signal)
×
301
                r = 1; /* wait */
302
        else {
303
                r = unit_kill_context(
×
304
                                UNIT(s),
×
305
                                state != SCOPE_STOP_SIGTERM ? KILL_KILL :
306
                                s->was_abandoned            ? KILL_TERMINATE_AND_LOG :
×
307
                                                              KILL_TERMINATE);
308
                if (r < 0) {
×
309
                        log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
×
310
                        goto fail;
×
311
                }
312
        }
313

314
        if (r > 0) {
×
315
                r = scope_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
×
316
                if (r < 0) {
×
317
                        log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
×
318
                        goto fail;
×
319
                }
320

321
                scope_set_state(s, state);
×
322
        } else if (state == SCOPE_STOP_SIGTERM)
×
323
                scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
×
324
        else
325
                scope_enter_dead(s, SCOPE_SUCCESS);
×
326

327
        return;
328

329
fail:
×
330
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
331
}
332

333
static int scope_enter_start_chown(Scope *s) {
×
334
        Unit *u = UNIT(ASSERT_PTR(s));
×
335
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
336
        int r;
×
337

338
        assert(s->user);
×
339

340
        if (!s->cgroup_runtime)
×
341
                return -EINVAL;
342

343
        r = scope_arm_timer(s, /* relative= */ true, u->manager->defaults.timeout_start_usec);
×
344
        if (r < 0)
×
345
                return r;
346

347
        r = unit_fork_helper_process(u, "(sd-chown-cgroup)", /* into_cgroup= */ true, &pidref);
×
348
        if (r < 0)
1✔
349
                goto fail;
×
350

351
        if (r == 0) {
1✔
352
                uid_t uid = UID_INVALID;
1✔
353
                gid_t gid = GID_INVALID;
1✔
354

355
                if (!isempty(s->user)) {
1✔
356
                        const char *user = s->user;
1✔
357

358
                        r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
1✔
359
                        if (r < 0) {
1✔
360
                                log_unit_error_errno(UNIT(s), r, "Failed to resolve user \"%s\": %m", user);
×
361
                                _exit(EXIT_USER);
×
362
                        }
363
                }
364

365
                if (!isempty(s->group)) {
1✔
366
                        const char *group = s->group;
×
367

368
                        r = get_group_creds(&group, &gid, 0);
×
369
                        if (r < 0) {
×
370
                                log_unit_error_errno(UNIT(s), r, "Failed to resolve group \"%s\": %m", group);
×
371
                                _exit(EXIT_GROUP);
×
372
                        }
373
                }
374

375
                r = cg_set_access(s->cgroup_runtime->cgroup_path, uid, gid);
1✔
376
                if (r < 0) {
1✔
377
                        log_unit_error_errno(UNIT(s), r, "Failed to adjust control group access: %m");
×
378
                        _exit(EXIT_CGROUP);
×
379
                }
380

381
                _exit(EXIT_SUCCESS);
1✔
382
        }
383

384
        r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
×
385
        if (r < 0)
×
386
                goto fail;
×
387

388
        scope_set_state(s, SCOPE_START_CHOWN);
×
389

390
        return 1;
391
fail:
×
392
        s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
×
393
        return r;
×
394
}
395

396
static int scope_enter_running(Scope *s) {
16✔
397
        Unit *u = UNIT(ASSERT_PTR(s));
16✔
398
        int r;
16✔
399

400
        (void) bus_scope_track_controller(s);
16✔
401

402
        r = unit_acquire_invocation_id(u);
16✔
403
        if (r < 0)
16✔
404
                return r;
405

406
        unit_export_state_files(u);
16✔
407

408
        r = unit_attach_pids_to_cgroup(u, u->pids, NULL);
16✔
409
        if (r < 0) {
16✔
410
                log_unit_warning_errno(u, r, "Failed to add PIDs to scope's control group: %m");
×
411
                goto fail;
×
412
        }
413
        if (r == 0) {
16✔
UNCOV
414
                r = log_unit_warning_errno(u, SYNTHETIC_ERRNO(ECHILD), "No PIDs left to attach to the scope's control group, refusing.");
×
UNCOV
415
                goto fail;
×
416
        }
417
        log_unit_debug(u, "%i %s added to scope's control group.", r, r == 1 ? "process" : "processes");
16✔
418

419
        s->result = SCOPE_SUCCESS;
16✔
420

421
        scope_set_state(s, SCOPE_RUNNING);
16✔
422

423
        /* Set the maximum runtime timeout. */
424
        scope_arm_timer(s, /* relative= */ false, scope_running_timeout(s));
16✔
425

426
        /* Unwatch all pids we've just added to cgroup. We rely on empty notifications there. */
427
        unit_unwatch_all_pids(u);
16✔
428

429
        return 1;
16✔
430

UNCOV
431
fail:
×
UNCOV
432
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
UNCOV
433
        return r;
×
434
}
435

436
static int scope_start(Unit *u) {
16✔
437
        Scope *s = ASSERT_PTR(SCOPE(u));
16✔
438

439
        if (unit_has_name(u, SPECIAL_INIT_SCOPE))
16✔
440
                return -EPERM;
441

442
        if (s->state == SCOPE_FAILED)
16✔
443
                return -EPERM;
444

445
        /* We can't fulfill this right now, please try again later */
446
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
16✔
447
                return -EAGAIN;
448

449
        assert(s->state == SCOPE_DEAD);
16✔
450

451
        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
16✔
452
                return -ENOENT;
453

454
        (void) unit_realize_cgroup(u);
16✔
455
        (void) unit_reset_accounting(u);
16✔
456

457
        /* We check only for User= option to keep behavior consistent with logic for service units,
458
         * i.e. having 'Delegate=true Group=foo' w/o specifying User= has no effect. */
459
        if (s->user && unit_cgroup_delegate(u))
16✔
460
                return scope_enter_start_chown(s);
×
461

462
        return scope_enter_running(s);
16✔
463
}
464

465
static int scope_stop(Unit *u) {
×
466
        Scope *s = ASSERT_PTR(SCOPE(u));
×
467

468
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
×
469
                return 0;
470

471
        assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
×
472

473
        scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
×
474
        return 1;
×
475
}
476

477
static void scope_reset_failed(Unit *u) {
1✔
478
        Scope *s = ASSERT_PTR(SCOPE(u));
1✔
479

480
        if (s->state == SCOPE_FAILED)
1✔
481
                scope_set_state(s, SCOPE_DEAD);
×
482

483
        s->result = SCOPE_SUCCESS;
1✔
484
}
1✔
485

486
static int scope_get_timeout(Unit *u, usec_t *timeout) {
×
487
        Scope *s = ASSERT_PTR(SCOPE(u));
×
488
        usec_t t;
×
489
        int r;
×
490

491
        if (!s->timer_event_source)
×
492
                return 0;
×
493

494
        r = sd_event_source_get_time(s->timer_event_source, &t);
×
495
        if (r < 0)
×
496
                return r;
497
        if (t == USEC_INFINITY)
×
498
                return 0;
499

500
        *timeout = t;
×
501
        return 1;
×
502
}
503

504
static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
121✔
505
        Scope *s = ASSERT_PTR(SCOPE(u));
121✔
506
        PidRef *pid;
121✔
507

508
        assert(f);
121✔
509
        assert(fds);
121✔
510

511
        (void) serialize_item(f, "state", scope_state_to_string(s->state));
121✔
512
        (void) serialize_bool(f, "was-abandoned", s->was_abandoned);
121✔
513

514
        if (s->controller)
121✔
515
                (void) serialize_item(f, "controller", s->controller);
×
516

517
        SET_FOREACH(pid, u->pids)
122✔
518
                serialize_pidref(f, fds, "pids", pid);
1✔
519

520
        return 0;
121✔
521
}
522

523
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
196✔
524
        Scope *s = ASSERT_PTR(SCOPE(u));
196✔
525
        int r;
196✔
526

527
        assert(key);
196✔
528
        assert(value);
196✔
529
        assert(fds);
196✔
530

531
        if (streq(key, "state")) {
196✔
532
                ScopeState state;
97✔
533

534
                state = scope_state_from_string(value);
97✔
535
                if (state < 0)
97✔
536
                        log_unit_debug(u, "Failed to parse state value: %s", value);
×
537
                else
538
                        s->deserialized_state = state;
97✔
539

540
        } else if (streq(key, "was-abandoned")) {
99✔
541
                int k;
97✔
542

543
                k = parse_boolean(value);
97✔
544
                if (k < 0)
97✔
545
                        log_unit_debug(u, "Failed to parse boolean value: %s", value);
×
546
                else
547
                        s->was_abandoned = k;
97✔
548
        } else if (streq(key, "controller")) {
2✔
549

550
                r = free_and_strdup(&s->controller, value);
×
551
                if (r < 0)
×
552
                        return log_oom();
×
553

554
        } else if (streq(key, "pids")) {
2✔
555
                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
2✔
556

557
                /* We don't check if we already received the pid before here because unit_watch_pidref()
558
                 * does this check internally and discards the new pidref if we already received it before. */
559
                if (deserialize_pidref(fds, value, &pidref) >= 0) {
2✔
560
                        r = unit_watch_pidref(u, &pidref, /* exclusive= */ false);
2✔
561
                        if (r < 0)
2✔
562
                                log_unit_debug(u, "Failed to watch PID, ignoring: %s", value);
×
563
                }
564
        } else
565
                log_unit_debug(u, "Unknown serialization key: %s", key);
×
566

567
        return 0;
568
}
569

570
static void scope_notify_cgroup_empty_event(Unit *u) {
8✔
571
        Scope *s = ASSERT_PTR(SCOPE(u));
8✔
572

573
        log_unit_debug(u, "cgroup is empty");
8✔
574

575
        if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
8✔
576
                scope_enter_dead(s, SCOPE_SUCCESS);
8✔
577
}
8✔
578

579
static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
×
580
        Scope *s = ASSERT_PTR(SCOPE(u));
×
581

582
        if (managed_oom)
×
583
                log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
×
584
        else
585
                log_unit_debug(u, "Process of control group was killed by the OOM killer.");
×
586

587
        if (s->oom_policy == OOM_CONTINUE)
×
588
                return;
589

590
        switch (s->state) {
×
591

592
        case SCOPE_START_CHOWN:
×
593
        case SCOPE_RUNNING:
594
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_OOM_KILL);
×
595
                break;
×
596

597
        case SCOPE_STOP_SIGTERM:
×
598
                scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_OOM_KILL);
×
599
                break;
×
600

601
        case SCOPE_STOP_SIGKILL:
×
602
                if (s->result == SCOPE_SUCCESS)
×
603
                        s->result = SCOPE_FAILURE_OOM_KILL;
×
604
                break;
605
        /* SCOPE_DEAD, SCOPE_ABANDONED, and SCOPE_FAILED end up in default */
606
        default:
×
607
                ;
×
608
        }
609
}
610

611
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
2,717✔
612
        Scope *s = ASSERT_PTR(SCOPE(u));
2,717✔
613

614
        if (s->state == SCOPE_START_CHOWN) {
2,717✔
615
                if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
×
616
                        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
617
                else
618
                        scope_enter_running(s);
×
619
                return;
×
620
        }
621
}
622

623
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
×
624
        Scope *s = ASSERT_PTR(SCOPE(userdata));
×
625

626
        assert(s->timer_event_source == source);
×
627

628
        switch (s->state) {
×
629

630
        case SCOPE_RUNNING:
631
                log_unit_warning(UNIT(s), "Scope reached runtime time limit. Stopping.");
×
632
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_TIMEOUT);
×
633
                break;
×
634

635
        case SCOPE_STOP_SIGTERM:
×
636
                if (s->kill_context.send_sigkill) {
×
637
                        log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
×
638
                        scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
×
639
                } else {
640
                        log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
×
641
                        scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
642
                }
643

644
                break;
645

646
        case SCOPE_STOP_SIGKILL:
647
                log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
×
648
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
649
                break;
×
650

651
        case SCOPE_START_CHOWN:
652
                log_unit_warning(UNIT(s), "User lookup timed out. Entering failed state.");
×
653
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
654
                break;
×
655

656
        default:
×
657
                assert_not_reached();
×
658
        }
659

660
        return 0;
×
661
}
662

663
int scope_abandon(Scope *s) {
7✔
664
        assert(s);
7✔
665

666
        if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
7✔
667
                return -EPERM;
668

669
        if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
7✔
670
                return -ESTALE;
671

672
        s->was_abandoned = true;
5✔
673

674
        s->controller = mfree(s->controller);
5✔
675
        s->controller_track = sd_bus_track_unref(s->controller_track);
5✔
676

677
        scope_set_state(s, SCOPE_ABANDONED);
5✔
678

679
        return 0;
5✔
680
}
681

682
static UnitActiveState scope_active_state(Unit *u) {
14,210✔
683
        Scope *s = ASSERT_PTR(SCOPE(u));
14,210✔
684

685
        return state_translation_table[s->state];
14,210✔
686
}
687

688
static const char *scope_sub_state_to_string(Unit *u) {
148✔
689
        Scope *s = ASSERT_PTR(SCOPE(u));
148✔
690

691
        return scope_state_to_string(s->state);
148✔
692
}
693

694
static void scope_enumerate_perpetual(Manager *m) {
274✔
695
        Unit *u;
274✔
696
        int r;
274✔
697

698
        assert(m);
274✔
699

700
        /* Let's unconditionally add the "init.scope" special unit
701
         * that encapsulates PID 1. Note that PID 1 already is in the
702
         * cgroup for this, we hence just need to allocate the object
703
         * for it and that's it. */
704

705
        u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
274✔
706
        if (!u) {
274✔
707
                r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
274✔
708
                if (r < 0)
274✔
709
                        return (void) log_error_errno(r, "Failed to allocate the special %s unit: %m",
×
710
                                                      SPECIAL_INIT_SCOPE);
711
        }
712

713
        u->transient = true;
274✔
714
        u->perpetual = true;
274✔
715
        SCOPE(u)->deserialized_state = SCOPE_RUNNING;
274✔
716

717
        unit_add_to_load_queue(u);
274✔
718
        unit_add_to_dbus_queue(u);
274✔
719
        /* Enqueue an explicit cgroup realization here. Unlike other cgroups this one already exists and is
720
         * populated (by us, after all!) already, even when we are not in a reload cycle. Hence we cannot
721
         * apply the settings at creation time anymore, but let's at least apply them asynchronously. */
722
        unit_add_to_cgroup_realize_queue(u);
274✔
723
}
724

725
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
726
        [SCOPE_SUCCESS]           = "success",
727
        [SCOPE_FAILURE_RESOURCES] = "resources",
728
        [SCOPE_FAILURE_TIMEOUT]   = "timeout",
729
        [SCOPE_FAILURE_OOM_KILL]  = "oom-kill",
730
};
731

732
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
192✔
733

734
const UnitVTable scope_vtable = {
735
        .object_size = sizeof(Scope),
736
        .cgroup_context_offset = offsetof(Scope, cgroup_context),
737
        .kill_context_offset = offsetof(Scope, kill_context),
738
        .cgroup_runtime_offset = offsetof(Scope, cgroup_runtime),
739

740
        .sections =
741
                "Unit\0"
742
                "Scope\0"
743
                "Install\0",
744
        .private_section = "Scope",
745

746
        .can_transient = true,
747
        .can_delegate = true,
748
        .can_fail = true,
749
        .once_only = true,
750
        .can_set_managed_oom = true,
751

752
        .init = scope_init,
753
        .load = scope_load,
754
        .done = scope_done,
755

756
        .coldplug = scope_coldplug,
757

758
        .dump = scope_dump,
759

760
        .start = scope_start,
761
        .stop = scope_stop,
762

763
        .freezer_action = unit_cgroup_freezer_action,
764

765
        .get_timeout = scope_get_timeout,
766

767
        .serialize = scope_serialize,
768
        .deserialize_item = scope_deserialize_item,
769

770
        .active_state = scope_active_state,
771
        .sub_state_to_string = scope_sub_state_to_string,
772

773
        .sigchld_event = scope_sigchld_event,
774

775
        .reset_failed = scope_reset_failed,
776

777
        .notify_cgroup_empty = scope_notify_cgroup_empty_event,
778
        .notify_cgroup_oom = scope_notify_cgroup_oom_event,
779

780
        .bus_set_property = bus_scope_set_property,
781
        .bus_commit_properties = bus_scope_commit_properties,
782

783
        .enumerate_perpetual = scope_enumerate_perpetual,
784
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc