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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

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

3
#include <errno.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "cgroup-setup.h"
8
#include "dbus-scope.h"
9
#include "dbus-unit.h"
10
#include "exit-status.h"
11
#include "load-dropin.h"
12
#include "log.h"
13
#include "manager.h"
14
#include "process-util.h"
15
#include "random-util.h"
16
#include "scope.h"
17
#include "serialize.h"
18
#include "special.h"
19
#include "string-table.h"
20
#include "string-util.h"
21
#include "strv.h"
22
#include "unit-name.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) {
339✔
39
        Scope *s = ASSERT_PTR(SCOPE(u));
339✔
40

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

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

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

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

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

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

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

65
        assert(s);
327✔
66

67
        if (s->runtime_rand_extra_usec != 0) {
327✔
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,
327✔
73
                                 s->runtime_max_usec),
74
                        delta);
75
}
76

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

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

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

86
        assert(s);
340✔
87

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

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

94
        if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN, SCOPE_RUNNING))
340✔
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))
340✔
98
                unit_unwatch_all_pids(UNIT(s));
8✔
99

100
        if (state != old_state)
340✔
101
                log_unit_debug(UNIT(s), "Changed %s -> %s",
340✔
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);
340✔
105
}
340✔
106

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

110
        assert(s);
329✔
111

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

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

124
        return 0;
125
}
126

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

131
        if (set_isempty(UNIT(s)->pids) &&
329✔
132
            !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
528✔
133
            !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
215✔
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) {
329✔
140
        assert(u);
329✔
141

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

145
        u->transient = true;
272✔
146
        u->perpetual = true;
272✔
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;
272✔
152

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

159
        return 1;
160
}
161

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

214
        case SCOPE_RUNNING:
311✔
215
                return scope_running_timeout(s);
311✔
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) {
313✔
227
        Scope *s = ASSERT_PTR(SCOPE(u));
313✔
228
        int r;
313✔
229

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

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

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

239
        if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED) && u->pids) {
311✔
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);
311✔
249

250
        scope_set_state(s, s->deserialized_state);
311✔
251
        return 0;
311✔
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✔
414
                r = log_unit_warning_errno(u, SYNTHETIC_ERRNO(ECHILD), "No PIDs left to attach to the scope's control group, refusing.");
×
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

431
fail:
×
432
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
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) {
2✔
478
        Scope *s = ASSERT_PTR(SCOPE(u));
2✔
479

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

483
        s->result = SCOPE_SUCCESS;
2✔
484
}
2✔
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) {
122✔
505
        Scope *s = ASSERT_PTR(SCOPE(u));
122✔
506
        PidRef *pid;
122✔
507

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

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

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

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

520
        return 0;
122✔
521
}
522

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

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

531
        if (streq(key, "state")) {
200✔
532
                ScopeState state;
98✔
533

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

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

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

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

554
        } else if (streq(key, "pids")) {
4✔
555
                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
4✔
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) {
4✔
560
                        r = unit_watch_pidref(u, &pidref, /* exclusive= */ false);
4✔
561
                        if (r < 0)
4✔
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,633✔
612
        Scope *s = ASSERT_PTR(SCOPE(u));
2,633✔
613

614
        if (s->state == SCOPE_START_CHOWN) {
2,633✔
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,246✔
683
        Scope *s = ASSERT_PTR(SCOPE(u));
14,246✔
684

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

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

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

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

698
        assert(m);
272✔
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);
272✔
706
        if (!u) {
272✔
707
                r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
272✔
708
                if (r < 0)  {
272✔
709
                        log_error_errno(r, "Failed to allocate the special " SPECIAL_INIT_SCOPE " unit: %m");
×
710
                        return;
×
711
                }
712
        }
713

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

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

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

733
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
192✔
734

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

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

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

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

757
        .coldplug = scope_coldplug,
758

759
        .dump = scope_dump,
760

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

764
        .freezer_action = unit_cgroup_freezer_action,
765

766
        .get_timeout = scope_get_timeout,
767

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

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

774
        .sigchld_event = scope_sigchld_event,
775

776
        .reset_failed = scope_reset_failed,
777

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

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

784
        .enumerate_perpetual = scope_enumerate_perpetual,
785
};
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