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

systemd / systemd / 19448983682

17 Nov 2025 11:32PM UTC coverage: 72.503% (-0.2%) from 72.719%
19448983682

push

github

web-flow
core/unit: unit_process_job() tweaks (#39753)

6 of 8 new or added lines in 1 file covered. (75.0%)

3363 existing lines in 68 files now uncovered.

308308 of 425234 relevant lines covered (72.5%)

1141671.45 hits per line

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

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

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

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

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

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

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

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

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

65
        assert(s);
443✔
66

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

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

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

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

86
        assert(s);
655✔
87

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

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

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

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

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

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

110
        assert(s);
455✔
111

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

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

124
        return 0;
125
}
126

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

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

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

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

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

159
        return 1;
160
}
161

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

239
        bus_scope_track_controller(s);
331✔
240

241
        scope_set_state(s, s->deserialized_state);
331✔
242
        return 0;
331✔
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) {
112✔
268
        assert(s);
112✔
269

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

273
        unit_log_result(UNIT(s), s->result == SCOPE_SUCCESS, scope_result_to_string(s->result));
112✔
274
        scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
223✔
275
}
112✔
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, "Failed to resolve user \"%s\": %m", user);
×
352
                                _exit(EXIT_USER);
×
353
                        }
354
                }
355

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

359
                        r = get_group_creds(&group, &gid, 0);
×
360
                        if (r < 0) {
×
361
                                log_unit_error_errno(UNIT(s), r, "Failed to resolve group \"%s\": %m", group);
×
362
                                _exit(EXIT_GROUP);
×
363
                        }
364
                }
365

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

372
                _exit(EXIT_SUCCESS);
1✔
373
        }
374

375
        r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
×
376
        if (r < 0)
×
377
                goto fail;
×
378

379
        scope_set_state(s, SCOPE_START_CHOWN);
×
380

381
        return 1;
382
fail:
×
383
        s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
×
384
        return r;
×
385
}
386

387
static int scope_enter_running(Scope *s) {
120✔
388
        Unit *u = UNIT(ASSERT_PTR(s));
120✔
389
        int r;
120✔
390

391
        (void) bus_scope_track_controller(s);
120✔
392

393
        r = unit_acquire_invocation_id(u);
120✔
394
        if (r < 0)
120✔
395
                return r;
396

397
        unit_export_state_files(u);
120✔
398

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

410
        s->result = SCOPE_SUCCESS;
119✔
411

412
        scope_set_state(s, SCOPE_RUNNING);
119✔
413

414
        /* Set the maximum runtime timeout. */
415
        scope_arm_timer(s, /* relative= */ false, scope_running_timeout(s));
119✔
416

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

420
        return 1;
119✔
421

422
fail:
1✔
423
        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
1✔
424
        return r;
1✔
425
}
426

427
static int scope_start(Unit *u) {
120✔
428
        Scope *s = ASSERT_PTR(SCOPE(u));
120✔
429

430
        if (unit_has_name(u, SPECIAL_INIT_SCOPE))
120✔
431
                return -EPERM;
432

433
        if (s->state == SCOPE_FAILED)
120✔
434
                return -EPERM;
435

436
        /* We can't fulfill this right now, please try again later */
437
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
120✔
438
                return -EAGAIN;
439

440
        assert(s->state == SCOPE_DEAD);
120✔
441

442
        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
120✔
443
                return -ENOENT;
444

445
        (void) unit_realize_cgroup(u);
120✔
446
        (void) unit_reset_accounting(u);
120✔
447

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

453
        return scope_enter_running(s);
120✔
454
}
455

456
static int scope_stop(Unit *u) {
×
457
        Scope *s = ASSERT_PTR(SCOPE(u));
×
458

459
        if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
×
460
                return 0;
461

462
        assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
×
463

464
        scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
×
465
        return 1;
×
466
}
467

468
static void scope_reset_failed(Unit *u) {
2✔
469
        Scope *s = ASSERT_PTR(SCOPE(u));
2✔
470

471
        if (s->state == SCOPE_FAILED)
2✔
472
                scope_set_state(s, SCOPE_DEAD);
×
473

474
        s->result = SCOPE_SUCCESS;
2✔
475
}
2✔
476

477
static int scope_get_timeout(Unit *u, usec_t *timeout) {
×
478
        Scope *s = ASSERT_PTR(SCOPE(u));
×
479
        usec_t t;
×
480
        int r;
×
481

482
        if (!s->timer_event_source)
×
483
                return 0;
×
484

485
        r = sd_event_source_get_time(s->timer_event_source, &t);
×
486
        if (r < 0)
×
487
                return r;
488
        if (t == USEC_INFINITY)
×
489
                return 0;
490

491
        *timeout = t;
×
492
        return 1;
×
493
}
494

495
static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
123✔
496
        Scope *s = ASSERT_PTR(SCOPE(u));
123✔
497
        PidRef *pid;
123✔
498

499
        assert(f);
123✔
500
        assert(fds);
123✔
501

502
        (void) serialize_item(f, "state", scope_state_to_string(s->state));
123✔
503
        (void) serialize_bool(f, "was-abandoned", s->was_abandoned);
123✔
504

505
        (void) serialize_item(f, "controller", s->controller);
123✔
506

507
        SET_FOREACH(pid, u->pids)
123✔
UNCOV
508
                serialize_pidref(f, fds, "pids", pid);
×
509

510
        return 0;
123✔
511
}
512

513
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
190✔
514
        Scope *s = ASSERT_PTR(SCOPE(u));
190✔
515
        int r;
190✔
516

517
        assert(key);
190✔
518
        assert(value);
190✔
519
        assert(fds);
190✔
520

521
        if (streq(key, "state")) {
190✔
522
                ScopeState state;
95✔
523

524
                state = scope_state_from_string(value);
95✔
525
                if (state < 0)
95✔
526
                        log_unit_debug(u, "Failed to parse state value: %s", value);
×
527
                else
528
                        s->deserialized_state = state;
95✔
529

530
        } else if (streq(key, "was-abandoned")) {
95✔
531
                int k;
95✔
532

533
                k = parse_boolean(value);
95✔
534
                if (k < 0)
95✔
535
                        log_unit_debug(u, "Failed to parse boolean value: %s", value);
×
536
                else
537
                        s->was_abandoned = k;
95✔
UNCOV
538
        } else if (streq(key, "controller")) {
×
539

540
                r = free_and_strdup(&s->controller, value);
×
541
                if (r < 0)
×
542
                        return log_oom();
×
543

UNCOV
544
        } else if (streq(key, "pids")) {
×
UNCOV
545
                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
546

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

557
        return 0;
558
}
559

560
static void scope_notify_cgroup_empty_event(Unit *u) {
111✔
561
        Scope *s = ASSERT_PTR(SCOPE(u));
111✔
562

563
        log_unit_debug(u, "cgroup is empty");
111✔
564

565
        if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
111✔
566
                scope_enter_dead(s, SCOPE_SUCCESS);
111✔
567
}
111✔
568

569
static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
×
570
        Scope *s = ASSERT_PTR(SCOPE(u));
×
571

572
        if (managed_oom)
×
573
                log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
×
574
        else
575
                log_unit_debug(u, "Process of control group was killed by the OOM killer.");
×
576

577
        if (s->oom_policy == OOM_CONTINUE)
×
578
                return;
579

580
        switch (s->state) {
×
581

582
        case SCOPE_START_CHOWN:
×
583
        case SCOPE_RUNNING:
584
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_OOM_KILL);
×
585
                break;
×
586

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

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

601
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
3,464✔
602
        Scope *s = ASSERT_PTR(SCOPE(u));
3,464✔
603

604
        if (s->state == SCOPE_START_CHOWN) {
3,464✔
605
                if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
×
606
                        scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
×
607
                else
608
                        scope_enter_running(s);
×
609
                return;
×
610
        }
611
}
612

613
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
×
614
        Scope *s = ASSERT_PTR(SCOPE(userdata));
×
615

616
        assert(s->timer_event_source == source);
×
617

618
        switch (s->state) {
×
619

620
        case SCOPE_RUNNING:
621
                log_unit_warning(UNIT(s), "Scope reached runtime time limit. Stopping.");
×
622
                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_TIMEOUT);
×
623
                break;
×
624

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

634
                break;
635

636
        case SCOPE_STOP_SIGKILL:
637
                log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
×
638
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
639
                break;
×
640

641
        case SCOPE_START_CHOWN:
642
                log_unit_warning(UNIT(s), "User lookup timed out. Entering failed state.");
×
643
                scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
×
644
                break;
×
645

646
        default:
×
647
                assert_not_reached();
×
648
        }
649

650
        return 0;
×
651
}
652

653
int scope_abandon(Scope *s) {
103✔
654
        assert(s);
103✔
655

656
        if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
103✔
657
                return -EPERM;
658

659
        if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
103✔
660
                return -ESTALE;
661

662
        s->was_abandoned = true;
93✔
663

664
        s->controller = mfree(s->controller);
93✔
665
        s->controller_track = sd_bus_track_unref(s->controller_track);
93✔
666

667
        scope_set_state(s, SCOPE_ABANDONED);
93✔
668

669
        return 0;
93✔
670
}
671

672
static UnitActiveState scope_active_state(Unit *u) {
21,067✔
673
        Scope *s = ASSERT_PTR(SCOPE(u));
21,067✔
674

675
        return state_translation_table[s->state];
21,067✔
676
}
677

678
static const char *scope_sub_state_to_string(Unit *u) {
663✔
679
        Scope *s = ASSERT_PTR(SCOPE(u));
663✔
680

681
        return scope_state_to_string(s->state);
663✔
682
}
683

684
static void scope_enumerate_perpetual(Manager *m) {
287✔
685
        Unit *u;
287✔
686
        int r;
287✔
687

688
        assert(m);
287✔
689

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

695
        u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
287✔
696
        if (!u) {
287✔
697
                r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
287✔
698
                if (r < 0)
287✔
699
                        return (void) log_error_errno(r, "Failed to allocate the special %s unit: %m",
×
700
                                                      SPECIAL_INIT_SCOPE);
701
        }
702

703
        u->transient = true;
287✔
704
        u->perpetual = true;
287✔
705
        SCOPE(u)->deserialized_state = SCOPE_RUNNING;
287✔
706

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

715
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
716
        [SCOPE_SUCCESS]           = "success",
717
        [SCOPE_FAILURE_RESOURCES] = "resources",
718
        [SCOPE_FAILURE_TIMEOUT]   = "timeout",
719
        [SCOPE_FAILURE_OOM_KILL]  = "oom-kill",
720
};
721

722
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
812✔
723

724
const UnitVTable scope_vtable = {
725
        .object_size = sizeof(Scope),
726
        .cgroup_context_offset = offsetof(Scope, cgroup_context),
727
        .kill_context_offset = offsetof(Scope, kill_context),
728
        .cgroup_runtime_offset = offsetof(Scope, cgroup_runtime),
729

730
        .sections =
731
                "Unit\0"
732
                "Scope\0"
733
                "Install\0",
734
        .private_section = "Scope",
735

736
        .can_transient = true,
737
        .can_delegate = true,
738
        .can_fail = true,
739
        .once_only = true,
740
        .can_set_managed_oom = true,
741

742
        .init = scope_init,
743
        .load = scope_load,
744
        .done = scope_done,
745

746
        .coldplug = scope_coldplug,
747

748
        .dump = scope_dump,
749

750
        .start = scope_start,
751
        .stop = scope_stop,
752

753
        .freezer_action = unit_cgroup_freezer_action,
754

755
        .get_timeout = scope_get_timeout,
756

757
        .serialize = scope_serialize,
758
        .deserialize_item = scope_deserialize_item,
759

760
        .active_state = scope_active_state,
761
        .sub_state_to_string = scope_sub_state_to_string,
762

763
        .sigchld_event = scope_sigchld_event,
764

765
        .reset_failed = scope_reset_failed,
766

767
        .notify_cgroup_empty = scope_notify_cgroup_empty_event,
768
        .notify_cgroup_oom = scope_notify_cgroup_oom_event,
769

770
        .bus_set_property = bus_scope_set_property,
771
        .bus_commit_properties = bus_scope_commit_properties,
772

773
        .enumerate_perpetual = scope_enumerate_perpetual,
774
};
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