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

systemd / systemd / 20447389715

21 Dec 2025 07:31PM UTC coverage: 72.37% (-0.1%) from 72.5%
20447389715

push

github

DaanDeMeyer
mkosi: Use initrd as exitrd

Let's speed up image builds by avoiding building
an exitrd and instead reusing the initrd image for
the same purpose.

308584 of 426400 relevant lines covered (72.37%)

1134231.7 hits per line

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

61.52
/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) {
643✔
39
        Scope *s = ASSERT_PTR(SCOPE(u));
643✔
40

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

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

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

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

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

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

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

65
        assert(s);
440✔
66

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

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

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

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

86
        assert(s);
645✔
87

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

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

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

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

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

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

110
        assert(s);
442✔
111

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

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

124
        return 0;
125
}
126

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

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

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

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

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

159
        return 1;
160
}
161

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

239
        bus_scope_track_controller(s);
321✔
240

241
        scope_set_state(s, s->deserialized_state);
321✔
242
        return 0;
321✔
243
}
244

245
static void scope_dump(Unit *u, FILE *f, const char *prefix) {
7✔
246
        Scope *s = ASSERT_PTR(SCOPE(u));
7✔
247

248
        assert(f);
7✔
249
        assert(prefix);
7✔
250

251
        fprintf(f,
14✔
252
                "%sScope State: %s\n"
253
                "%sResult: %s\n"
254
                "%sRuntimeMaxSec: %s\n"
255
                "%sRuntimeRandomizedExtraSec: %s\n"
256
                "%sOOMPolicy: %s\n",
257
                prefix, scope_state_to_string(s->state),
258
                prefix, scope_result_to_string(s->result),
259
                prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
7✔
260
                prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
7✔
261
                prefix, oom_policy_to_string(s->oom_policy));
262

263
        cgroup_context_dump(u, f, prefix);
7✔
264
        kill_context_dump(&s->kill_context, f, prefix);
7✔
265
}
7✔
266

267
static void scope_enter_dead(Scope *s, ScopeResult f) {
111✔
268
        assert(s);
111✔
269

270
        if (s->result == SCOPE_SUCCESS)
111✔
271
                s->result = f;
111✔
272

273
        unit_log_result(UNIT(s), s->result == SCOPE_SUCCESS, scope_result_to_string(s->result));
111✔
274
        scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
222✔
275
}
111✔
276

277
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
×
278
        bool skip_signal = false;
×
279
        int r;
×
280

281
        assert(s);
×
282

283
        if (s->result == SCOPE_SUCCESS)
×
284
                s->result = f;
×
285

286
        /* If we have a controller set let's ask the controller nicely to terminate the scope, instead of us going
287
         * directly into SIGTERM berserk mode */
288
        if (state == SCOPE_STOP_SIGTERM)
×
289
                skip_signal = bus_scope_send_request_stop(s) > 0;
×
290

291
        if (skip_signal)
×
292
                r = 1; /* wait */
293
        else {
294
                r = unit_kill_context(
×
295
                                UNIT(s),
×
296
                                state != SCOPE_STOP_SIGTERM ? KILL_KILL :
297
                                s->was_abandoned            ? KILL_TERMINATE_AND_LOG :
×
298
                                                              KILL_TERMINATE);
299
                if (r < 0) {
×
300
                        log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
×
301
                        goto fail;
×
302
                }
303
        }
304

305
        if (r > 0) {
×
306
                r = scope_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
×
307
                if (r < 0) {
×
308
                        log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
×
309
                        goto fail;
×
310
                }
311

312
                scope_set_state(s, state);
×
313
        } else if (state == SCOPE_STOP_SIGTERM)
×
314
                scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
×
315
        else
316
                scope_enter_dead(s, SCOPE_SUCCESS);
×
317

318
        return;
319

320
fail:
×
321
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
322
}
323

324
static int scope_enter_start_chown(Scope *s) {
×
325
        Unit *u = UNIT(ASSERT_PTR(s));
×
326
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
327
        int r;
×
328

329
        assert(s->user);
×
330

331
        if (!s->cgroup_runtime)
×
332
                return -EINVAL;
333

334
        r = scope_arm_timer(s, /* relative= */ true, u->manager->defaults.timeout_start_usec);
×
335
        if (r < 0)
×
336
                return r;
337

338
        r = unit_fork_helper_process(u, "(sd-chown-cgroup)", /* into_cgroup= */ true, &pidref);
×
339
        if (r < 0)
1✔
340
                goto fail;
×
341

342
        if (r == 0) {
1✔
343
                uid_t uid = UID_INVALID;
1✔
344
                gid_t gid = GID_INVALID;
1✔
345

346
                if (!isempty(s->user)) {
1✔
347
                        const char *user = s->user;
1✔
348

349
                        r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
1✔
350
                        if (r < 0) {
1✔
351
                                log_unit_error_errno(UNIT(s), r,
×
352
                                                     "Failed to resolve user '%s': %s",
353
                                                     user, STRERROR_USER(r));
354
                                _exit(EXIT_USER);
×
355
                        }
356
                }
357

358
                if (!isempty(s->group)) {
1✔
359
                        const char *group = s->group;
×
360

361
                        r = get_group_creds(&group, &gid, 0);
×
362
                        if (r < 0) {
×
363
                                log_unit_error_errno(UNIT(s), r,
×
364
                                                     "Failed to resolve group '%s': %s",
365
                                                     group, STRERROR_GROUP(r));
366
                                _exit(EXIT_GROUP);
×
367
                        }
368
                }
369

370
                r = cg_set_access(s->cgroup_runtime->cgroup_path, uid, gid);
1✔
371
                if (r < 0) {
1✔
372
                        log_unit_error_errno(UNIT(s), r, "Failed to adjust control group access: %m");
×
373
                        _exit(EXIT_CGROUP);
×
374
                }
375

376
                _exit(EXIT_SUCCESS);
1✔
377
        }
378

379
        r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
×
380
        if (r < 0)
×
381
                goto fail;
×
382

383
        scope_set_state(s, SCOPE_START_CHOWN);
×
384

385
        return 1;
386
fail:
×
387
        s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
×
388
        return r;
×
389
}
390

391
static int scope_enter_running(Scope *s) {
119✔
392
        Unit *u = UNIT(ASSERT_PTR(s));
119✔
393
        int r;
119✔
394

395
        (void) bus_scope_track_controller(s);
119✔
396

397
        r = unit_acquire_invocation_id(u);
119✔
398
        if (r < 0)
119✔
399
                return r;
400

401
        unit_export_state_files(u);
119✔
402

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

414
        s->result = SCOPE_SUCCESS;
119✔
415

416
        scope_set_state(s, SCOPE_RUNNING);
119✔
417

418
        /* Set the maximum runtime timeout. */
419
        scope_arm_timer(s, /* relative= */ false, scope_running_timeout(s));
119✔
420

421
        /* Unwatch all pids we've just added to cgroup. We rely on empty notifications there. */
422
        unit_unwatch_all_pids(u);
119✔
423

424
        return 1;
119✔
425

426
fail:
×
427
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
428
        return r;
×
429
}
430

431
static int scope_start(Unit *u) {
119✔
432
        Scope *s = ASSERT_PTR(SCOPE(u));
119✔
433

434
        if (unit_has_name(u, SPECIAL_INIT_SCOPE))
119✔
435
                return -EPERM;
436

437
        if (s->state == SCOPE_FAILED)
119✔
438
                return -EPERM;
439

440
        /* We can't fulfill this right now, please try again later */
441
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
119✔
442
                return -EAGAIN;
443

444
        assert(s->state == SCOPE_DEAD);
119✔
445

446
        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
119✔
447
                return -ENOENT;
448

449
        (void) unit_realize_cgroup(u);
119✔
450
        (void) unit_reset_accounting(u);
119✔
451

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

457
        return scope_enter_running(s);
119✔
458
}
459

460
static int scope_stop(Unit *u) {
×
461
        Scope *s = ASSERT_PTR(SCOPE(u));
×
462

463
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
×
464
                return 0;
465

466
        assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
×
467

468
        scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
×
469
        return 1;
×
470
}
471

472
static void scope_reset_failed(Unit *u) {
2✔
473
        Scope *s = ASSERT_PTR(SCOPE(u));
2✔
474

475
        if (s->state == SCOPE_FAILED)
2✔
476
                scope_set_state(s, SCOPE_DEAD);
×
477

478
        s->result = SCOPE_SUCCESS;
2✔
479
}
2✔
480

481
static int scope_get_timeout(Unit *u, usec_t *timeout) {
×
482
        Scope *s = ASSERT_PTR(SCOPE(u));
×
483
        usec_t t;
×
484
        int r;
×
485

486
        if (!s->timer_event_source)
×
487
                return 0;
×
488

489
        r = sd_event_source_get_time(s->timer_event_source, &t);
×
490
        if (r < 0)
×
491
                return r;
492
        if (t == USEC_INFINITY)
×
493
                return 0;
494

495
        *timeout = t;
×
496
        return 1;
×
497
}
498

499
static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
115✔
500
        Scope *s = ASSERT_PTR(SCOPE(u));
115✔
501
        PidRef *pid;
115✔
502

503
        assert(f);
115✔
504
        assert(fds);
115✔
505

506
        (void) serialize_item(f, "state", scope_state_to_string(s->state));
115✔
507
        (void) serialize_bool(f, "was-abandoned", s->was_abandoned);
115✔
508

509
        (void) serialize_item(f, "controller", s->controller);
115✔
510

511
        SET_FOREACH(pid, u->pids)
115✔
512
                serialize_pidref(f, fds, "pids", pid);
×
513

514
        return 0;
115✔
515
}
516

517
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
176✔
518
        Scope *s = ASSERT_PTR(SCOPE(u));
176✔
519
        int r;
176✔
520

521
        assert(key);
176✔
522
        assert(value);
176✔
523
        assert(fds);
176✔
524

525
        if (streq(key, "state")) {
176✔
526
                ScopeState state;
88✔
527

528
                state = scope_state_from_string(value);
88✔
529
                if (state < 0)
88✔
530
                        log_unit_debug(u, "Failed to parse state value: %s", value);
×
531
                else
532
                        s->deserialized_state = state;
88✔
533

534
        } else if (streq(key, "was-abandoned")) {
88✔
535
                int k;
88✔
536

537
                k = parse_boolean(value);
88✔
538
                if (k < 0)
88✔
539
                        log_unit_debug(u, "Failed to parse boolean value: %s", value);
×
540
                else
541
                        s->was_abandoned = k;
88✔
542
        } else if (streq(key, "controller")) {
×
543

544
                r = free_and_strdup(&s->controller, value);
×
545
                if (r < 0)
×
546
                        return log_oom();
×
547

548
        } else if (streq(key, "pids")) {
×
549
                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
550

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

561
        return 0;
562
}
563

564
static void scope_notify_cgroup_empty_event(Unit *u) {
111✔
565
        Scope *s = ASSERT_PTR(SCOPE(u));
111✔
566

567
        log_unit_debug(u, "cgroup is empty");
111✔
568

569
        if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
111✔
570
                scope_enter_dead(s, SCOPE_SUCCESS);
111✔
571
}
111✔
572

573
static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
×
574
        Scope *s = ASSERT_PTR(SCOPE(u));
×
575

576
        if (managed_oom)
×
577
                log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
×
578
        else
579
                log_unit_debug(u, "Process of control group was killed by the OOM killer.");
×
580

581
        if (s->oom_policy == OOM_CONTINUE)
×
582
                return;
583

584
        switch (s->state) {
×
585

586
        case SCOPE_START_CHOWN:
×
587
        case SCOPE_RUNNING:
588
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_OOM_KILL);
×
589
                break;
×
590

591
        case SCOPE_STOP_SIGTERM:
×
592
                scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_OOM_KILL);
×
593
                break;
×
594

595
        case SCOPE_STOP_SIGKILL:
×
596
                if (s->result == SCOPE_SUCCESS)
×
597
                        s->result = SCOPE_FAILURE_OOM_KILL;
×
598
                break;
599
        /* SCOPE_DEAD, SCOPE_ABANDONED, and SCOPE_FAILED end up in default */
600
        default:
×
601
                ;
×
602
        }
603
}
604

605
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
3,394✔
606
        Scope *s = ASSERT_PTR(SCOPE(u));
3,394✔
607

608
        if (s->state == SCOPE_START_CHOWN) {
3,394✔
609
                if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
×
610
                        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
611
                else
612
                        scope_enter_running(s);
×
613
                return;
×
614
        }
615
}
616

617
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
×
618
        Scope *s = ASSERT_PTR(SCOPE(userdata));
×
619

620
        assert(s->timer_event_source == source);
×
621

622
        switch (s->state) {
×
623

624
        case SCOPE_RUNNING:
625
                log_unit_warning(UNIT(s), "Scope reached runtime time limit. Stopping.");
×
626
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_TIMEOUT);
×
627
                break;
×
628

629
        case SCOPE_STOP_SIGTERM:
×
630
                if (s->kill_context.send_sigkill) {
×
631
                        log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
×
632
                        scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
×
633
                } else {
634
                        log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
×
635
                        scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
636
                }
637

638
                break;
639

640
        case SCOPE_STOP_SIGKILL:
641
                log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
×
642
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
643
                break;
×
644

645
        case SCOPE_START_CHOWN:
646
                log_unit_warning(UNIT(s), "User lookup timed out. Entering failed state.");
×
647
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
648
                break;
×
649

650
        default:
×
651
                assert_not_reached();
×
652
        }
653

654
        return 0;
×
655
}
656

657
int scope_abandon(Scope *s) {
100✔
658
        assert(s);
100✔
659

660
        if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
100✔
661
                return -EPERM;
662

663
        if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
100✔
664
                return -ESTALE;
665

666
        s->was_abandoned = true;
94✔
667

668
        s->controller = mfree(s->controller);
94✔
669
        s->controller_track = sd_bus_track_unref(s->controller_track);
94✔
670

671
        scope_set_state(s, SCOPE_ABANDONED);
94✔
672

673
        return 0;
94✔
674
}
675

676
static UnitActiveState scope_active_state(Unit *u) {
21,252✔
677
        Scope *s = ASSERT_PTR(SCOPE(u));
21,252✔
678

679
        return state_translation_table[s->state];
21,252✔
680
}
681

682
static const char *scope_sub_state_to_string(Unit *u) {
654✔
683
        Scope *s = ASSERT_PTR(SCOPE(u));
654✔
684

685
        return scope_state_to_string(s->state);
654✔
686
}
687

688
static void scope_enumerate_perpetual(Manager *m) {
284✔
689
        Unit *u;
284✔
690
        int r;
284✔
691

692
        assert(m);
284✔
693

694
        /* Let's unconditionally add the "init.scope" special unit
695
         * that encapsulates PID 1. Note that PID 1 already is in the
696
         * cgroup for this, we hence just need to allocate the object
697
         * for it and that's it. */
698

699
        u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
284✔
700
        if (!u) {
284✔
701
                r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
284✔
702
                if (r < 0)
284✔
703
                        return (void) log_error_errno(r, "Failed to allocate the special %s unit: %m",
×
704
                                                      SPECIAL_INIT_SCOPE);
705
        }
706

707
        u->transient = true;
284✔
708
        u->perpetual = true;
284✔
709
        SCOPE(u)->deserialized_state = SCOPE_RUNNING;
284✔
710

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

719
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
720
        [SCOPE_SUCCESS]           = "success",
721
        [SCOPE_FAILURE_RESOURCES] = "resources",
722
        [SCOPE_FAILURE_TIMEOUT]   = "timeout",
723
        [SCOPE_FAILURE_OOM_KILL]  = "oom-kill",
724
};
725

726
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
802✔
727

728
const UnitVTable scope_vtable = {
729
        .object_size = sizeof(Scope),
730
        .cgroup_context_offset = offsetof(Scope, cgroup_context),
731
        .kill_context_offset = offsetof(Scope, kill_context),
732
        .cgroup_runtime_offset = offsetof(Scope, cgroup_runtime),
733

734
        .sections =
735
                "Unit\0"
736
                "Scope\0"
737
                "Install\0",
738
        .private_section = "Scope",
739

740
        .can_transient = true,
741
        .can_delegate = true,
742
        .can_fail = true,
743
        .once_only = true,
744
        .can_set_managed_oom = true,
745

746
        .init = scope_init,
747
        .load = scope_load,
748
        .done = scope_done,
749

750
        .coldplug = scope_coldplug,
751

752
        .dump = scope_dump,
753

754
        .start = scope_start,
755
        .stop = scope_stop,
756

757
        .freezer_action = unit_cgroup_freezer_action,
758

759
        .get_timeout = scope_get_timeout,
760

761
        .serialize = scope_serialize,
762
        .deserialize_item = scope_deserialize_item,
763

764
        .active_state = scope_active_state,
765
        .sub_state_to_string = scope_sub_state_to_string,
766

767
        .sigchld_event = scope_sigchld_event,
768

769
        .reset_failed = scope_reset_failed,
770

771
        .notify_cgroup_empty = scope_notify_cgroup_empty_event,
772
        .notify_cgroup_oom = scope_notify_cgroup_oom_event,
773

774
        .bus_set_property = bus_scope_set_property,
775
        .bus_commit_properties = bus_scope_commit_properties,
776

777
        .enumerate_perpetual = scope_enumerate_perpetual,
778
};
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