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

systemd / systemd / 20629511025

31 Dec 2025 02:58PM UTC coverage: 72.676% (+0.2%) from 72.439%
20629511025

push

github

web-flow
Support Bash completions for short option group in journalctl (#40214)

Currently, the Bash completions for journalctl tries to match the
previous word _**exactly**_, which leads to the following issue:
`journalctl -u dock` correctly auto completes to `journalctl -u
docker.service`, but `journalctl -eu` provides no completions at all,
which is a shame since I never use the `-u` option alone (almost always
`-eu` or `-efu`, I wish the `-e` option was the default but I digress).

The proposed solution is to assume words that start with only a single
dash and consist of only letters are short option groups and handle them
as if the previous word was the short option using the last character,
e.g. `-efu` -> `-u`.

309992 of 426542 relevant lines covered (72.68%)

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

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

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

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

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

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

58
        s->user = mfree(s->user);
647✔
59
        s->group = mfree(s->group);
647✔
60
}
647✔
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) {
443✔
78
        assert(s);
443✔
79

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

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

86
        assert(s);
647✔
87

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

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

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

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

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

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

110
        assert(s);
445✔
111

112
        if (!UNIT(s)->default_dependencies)
445✔
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) {
445✔
128
        assert(s);
445✔
129
        assert(UNIT(s)->load_state == UNIT_LOADED);
445✔
130

131
        if (set_isempty(UNIT(s)->pids) &&
445✔
132
            !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
560✔
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) {
445✔
140
        assert(u);
445✔
141

142
        if (!unit_has_name(u, SPECIAL_INIT_SCOPE))
445✔
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) {
445✔
163
        int r;
445✔
164

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

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

173
        if (s->oom_policy < 0)
445✔
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;
445✔
177

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

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

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

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

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

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

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

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

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

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

212
        switch (s->deserialized_state) {
324✔
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) {
324✔
227
        Scope *s = ASSERT_PTR(SCOPE(u));
324✔
228
        int r;
324✔
229

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

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

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

239
        bus_scope_track_controller(s);
324✔
240

241
        scope_set_state(s, s->deserialized_state);
324✔
242
        return 0;
324✔
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,533✔
606
        Scope *s = ASSERT_PTR(SCOPE(u));
3,533✔
607

608
        if (s->state == SCOPE_START_CHOWN) {
3,533✔
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;
93✔
667

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

671
        scope_set_state(s, SCOPE_ABANDONED);
93✔
672

673
        return 0;
93✔
674
}
675

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

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

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

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

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

692
        assert(m);
287✔
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);
287✔
700
        if (!u) {
287✔
701
                r = unit_new_for_name(m, sizeof(Scope), SPECIAL_INIT_SCOPE, &u);
287✔
702
                if (r < 0)
287✔
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;
287✔
708
        u->perpetual = true;
287✔
709
        SCOPE(u)->deserialized_state = SCOPE_RUNNING;
287✔
710

711
        unit_add_to_load_queue(u);
287✔
712
        unit_add_to_dbus_queue(u);
287✔
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);
287✔
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);
800✔
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