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

systemd / systemd / 29295695877

13 Jul 2026 11:19PM UTC coverage: 72.94% (-0.05%) from 72.994%
29295695877

push

github

web-flow
userdb: suppress userdb queries for backends indicating uid/gid/name range info via xattrs on entrypoint sockets (#42961)

Let's optimize userdb queries a bit: by encoding the covered UID/GID
ranges and user/group name patterns on the varlink entrypoint sockets
for userdb backends we can make them wake up less and reduce the work
triggered by queries.

81 of 92 new or added lines in 5 files covered. (88.04%)

5898 existing lines in 76 files now uncovered.

345436 of 473591 relevant lines covered (72.94%)

1320061.25 hits per line

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

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

3
#include <stdlib.h>
4
#include <sys/stat.h>
5
#include <unistd.h>
6

7
#include "sd-bus.h"
8

9
#include "alloc-util.h"
10
#include "bus-error.h"
11
#include "calendarspec.h"
12
#include "dbus-timer.h"
13
#include "dbus-unit.h"
14
#include "fs-util.h"
15
#include "manager.h"
16
#include "random-util.h"
17
#include "serialize.h"
18
#include "siphash24.h"
19
#include "special.h"
20
#include "string-table.h"
21
#include "string-util.h"
22
#include "strv.h"
23
#include "timer.h"
24
#include "unit.h"
25
#include "user-util.h"
26
#include "virt.h"
27

28
static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
29
        [TIMER_DEAD]    = UNIT_INACTIVE,
30
        [TIMER_WAITING] = UNIT_ACTIVE,
31
        [TIMER_RUNNING] = UNIT_ACTIVE,
32
        [TIMER_ELAPSED] = UNIT_ACTIVE,
33
        [TIMER_FAILED]  = UNIT_FAILED,
34
};
35

36
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
37

38
static void timer_init(Unit *u) {
968✔
39
        Timer *t = ASSERT_PTR(TIMER(u));
968✔
40

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

43
        t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
968✔
44
        t->next_elapse_realtime = USEC_INFINITY;
968✔
45
        t->accuracy_usec = u->manager->defaults.timer_accuracy_usec;
968✔
46
        t->remain_after_elapse = true;
968✔
47
}
968✔
48

49
void timer_free_values(Timer *t) {
973✔
50
        TimerValue *v;
973✔
51

52
        assert(t);
973✔
53

54
        while ((v = LIST_POP(value, t->values))) {
2,438✔
55
                calendar_spec_free(v->calendar_spec);
1,465✔
56
                free(v);
1,465✔
57
        }
58
}
973✔
59

60
static void timer_done(Unit *u) {
968✔
61
        Timer *t = ASSERT_PTR(TIMER(u));
968✔
62

63
        timer_free_values(t);
968✔
64

65
        t->monotonic_event_source = sd_event_source_disable_unref(t->monotonic_event_source);
968✔
66
        t->realtime_event_source = sd_event_source_disable_unref(t->realtime_event_source);
968✔
67

68
        t->stamp_path = mfree(t->stamp_path);
968✔
69
}
968✔
70

71
static int timer_verify(Timer *t) {
962✔
72
        assert(t);
962✔
73
        assert(UNIT(t)->load_state == UNIT_LOADED);
962✔
74

75
        if (!t->values && !t->on_clock_change && !t->on_timezone_change)
962✔
76
                return log_unit_error_errno(UNIT(t), SYNTHETIC_ERRNO(ENOEXEC), "Timer unit lacks value setting. Refusing.");
5✔
77

78
        return 0;
79
}
80

81
static int timer_add_default_dependencies(Timer *t) {
962✔
82
        int r;
962✔
83

84
        assert(t);
962✔
85

86
        if (!UNIT(t)->default_dependencies)
962✔
87
                return 0;
88

89
        r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
962✔
90
        if (r < 0)
962✔
91
                return r;
92

93
        if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
962✔
94
                r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
718✔
95
                if (r < 0)
718✔
96
                        return r;
97

98
                LIST_FOREACH(value, v, t->values) {
1,213✔
99
                        if (v->base != TIMER_CALENDAR)
961✔
100
                                continue;
495✔
101

102
                        FOREACH_STRING(target, SPECIAL_TIME_SYNC_TARGET, SPECIAL_TIME_SET_TARGET) {
1,398✔
103
                                r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, target, true, UNIT_DEPENDENCY_DEFAULT);
932✔
104
                                if (r < 0)
932✔
105
                                        return r;
×
106
                        }
107

108
                        break;
466✔
109
                }
110
        }
111

112
        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
962✔
113
}
114

115
static int timer_add_trigger_dependencies(Timer *t) {
962✔
116
        Unit *x;
962✔
117
        int r;
962✔
118

119
        assert(t);
962✔
120

121
        if (UNIT_TRIGGER(UNIT(t)))
962✔
122
                return 0;
962✔
123

124
        r = unit_load_related_unit(UNIT(t), ".service", &x);
962✔
125
        if (r < 0)
962✔
126
                return r;
127

128
        return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
962✔
129
}
130

131
static int timer_setup_persistent(Timer *t) {
962✔
132
        _cleanup_free_ char *stamp_path = NULL;
962✔
133
        int r;
962✔
134

135
        assert(t);
962✔
136

137
        if (!t->persistent)
962✔
138
                return 0;
139

140
        if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
460✔
141

142
                r = unit_add_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
460✔
143
                if (r < 0)
460✔
144
                        return r;
145

146
                stamp_path = strjoin("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
460✔
147
        } else {
148
                const char *e;
×
149

150
                e = getenv("XDG_DATA_HOME");
×
151
                if (e)
×
152
                        stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id);
×
153
                else {
154

155
                        _cleanup_free_ char *h = NULL;
×
156

157
                        r = get_home_dir(&h);
×
158
                        if (r < 0)
×
159
                                return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
×
160

161
                        stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id);
×
162
                }
163
        }
164

165
        if (!stamp_path)
460✔
166
                return log_oom();
×
167

168
        return free_and_replace(t->stamp_path, stamp_path);
460✔
169
}
170

171
static uint64_t timer_get_fixed_delay_hash(Timer *t) {
×
172
        static const uint8_t hash_key[] = {
×
173
                0x51, 0x0a, 0xdb, 0x76, 0x29, 0x51, 0x42, 0xc2,
174
                0x80, 0x35, 0xea, 0xe6, 0x8e, 0x3a, 0x37, 0xbd
175
        };
176

177
        struct siphash state;
×
178
        sd_id128_t machine_id;
×
179
        uid_t uid;
×
180
        int r;
×
181

182
        assert(t);
×
183

184
        uid = getuid();
×
185
        r = sd_id128_get_machine(&machine_id);
×
186
        if (r < 0) {
×
187
                log_unit_debug_errno(UNIT(t), r,
×
188
                                     "Failed to get machine ID for the fixed delay calculation, proceeding with 0: %m");
189
                machine_id = SD_ID128_NULL;
×
190
        }
191

192
        siphash24_init(&state, hash_key);
×
193
        siphash24_compress_typesafe(machine_id, &state);
×
194
        siphash24_compress_boolean(MANAGER_IS_SYSTEM(UNIT(t)->manager), &state);
×
195
        siphash24_compress_typesafe(uid, &state);
×
196
        siphash24_compress_string(UNIT(t)->id, &state);
×
197

198
        return siphash24_finalize(&state);
×
199
}
200

201
static int timer_load(Unit *u) {
975✔
202
        Timer *t = ASSERT_PTR(TIMER(u));
975✔
203
        int r;
975✔
204

205
        assert(u->load_state == UNIT_STUB);
975✔
206

207
        r = unit_load_fragment_and_dropin(u, true);
975✔
208
        if (r < 0)
975✔
209
                return r;
210

211
        if (u->load_state != UNIT_LOADED)
964✔
212
                return 0;
213

214
        /* This is a new unit? Then let's add in some extras */
215
        r = timer_add_trigger_dependencies(t);
962✔
216
        if (r < 0)
962✔
217
                return r;
218

219
        r = timer_setup_persistent(t);
962✔
220
        if (r < 0)
962✔
221
                return r;
222

223
        r = timer_add_default_dependencies(t);
962✔
224
        if (r < 0)
962✔
225
                return r;
226

227
        return timer_verify(t);
962✔
228
}
229

230
static void timer_dump(Unit *u, FILE *f, const char *prefix) {
3✔
231
        Timer *t = ASSERT_PTR(TIMER(u));
3✔
232
        Unit *trigger;
3✔
233

234
        assert(f);
3✔
235
        assert(prefix);
3✔
236

237
        trigger = UNIT_TRIGGER(u);
3✔
238

239
        fprintf(f,
22✔
240
                "%sTimer State: %s\n"
241
                "%sResult: %s\n"
242
                "%sUnit: %s\n"
243
                "%sPersistent: %s\n"
244
                "%sWakeSystem: %s\n"
245
                "%sAccuracy: %s\n"
246
                "%sRemainAfterElapse: %s\n"
247
                "%sFixedRandomDelay: %s\n"
248
                "%sOnClockChange: %s\n"
249
                "%sOnTimeZoneChange: %s\n"
250
                "%sDeferReactivation: %s\n",
251
                prefix, timer_state_to_string(t->state),
252
                prefix, timer_result_to_string(t->result),
253
                prefix, trigger ? trigger->id : "n/a",
254
                prefix, yes_no(t->persistent),
255
                prefix, yes_no(t->wake_system),
256
                prefix, FORMAT_TIMESPAN(t->accuracy_usec, 1),
3✔
257
                prefix, yes_no(t->remain_after_elapse),
258
                prefix, yes_no(t->fixed_random_delay),
259
                prefix, yes_no(t->on_clock_change),
260
                prefix, yes_no(t->on_timezone_change),
261
                prefix, yes_no(t->defer_reactivation));
262

263
        LIST_FOREACH(value, v, t->values)
7✔
264
                if (v->base == TIMER_CALENDAR) {
4✔
265
                        _cleanup_free_ char *p = NULL;
2✔
266

267
                        (void) calendar_spec_to_string(v->calendar_spec, &p);
2✔
268

269
                        fprintf(f,
2✔
270
                                "%s%s: %s\n",
271
                                prefix,
272
                                timer_base_to_string(v->base),
273
                                strna(p));
274
                } else
275
                        fprintf(f,
2✔
276
                                "%s%s: %s\n",
277
                                prefix,
278
                                timer_base_to_string(v->base),
279
                                FORMAT_TIMESPAN(v->value, 0));
2✔
280
}
3✔
281

282
static void timer_set_state(Timer *t, TimerState state) {
1,202✔
283
        TimerState old_state;
1,202✔
284

285
        assert(t);
1,202✔
286

287
        if (t->state != state)
1,202✔
288
                bus_unit_send_pending_change_signal(UNIT(t), false);
1,163✔
289

290
        old_state = t->state;
1,202✔
291
        t->state = state;
1,202✔
292

293
        if (state != TIMER_WAITING) {
1,202✔
294
                t->monotonic_event_source = sd_event_source_disable_unref(t->monotonic_event_source);
309✔
295
                t->realtime_event_source = sd_event_source_disable_unref(t->realtime_event_source);
309✔
296
                t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
309✔
297
                t->next_elapse_realtime = USEC_INFINITY;
309✔
298
        }
299

300
        if (state != old_state)
1,202✔
301
                log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
1,163✔
302

303
        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], /* reload_success= */ true);
1,202✔
304
}
1,202✔
305

306
static void timer_enter_waiting(Timer *t, bool time_change);
307

308
static int timer_coldplug(Unit *u) {
655✔
309
        Timer *t = ASSERT_PTR(TIMER(u));
655✔
310

311
        assert(t->state == TIMER_DEAD);
655✔
312

313
        if (t->deserialized_state == t->state)
655✔
314
                return 0;
315

316
        if (t->deserialized_state == TIMER_WAITING)
516✔
317
                timer_enter_waiting(t, false);
514✔
318
        else
319
                timer_set_state(t, t->deserialized_state);
2✔
320

321
        return 0;
322
}
323

324
static void timer_enter_dead(Timer *t, TimerResult f) {
289✔
325
        assert(t);
289✔
326

327
        if (t->result == TIMER_SUCCESS || f == TIMER_FAILURE_START_LIMIT_HIT)
289✔
328
                t->result = f;
289✔
329

330
        unit_log_result(UNIT(t), t->result == TIMER_SUCCESS, timer_result_to_string(t->result));
289✔
331
        timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
578✔
332
}
289✔
333

334
static void timer_enter_elapsed(Timer *t, bool leave_around) {
2✔
335
        assert(t);
2✔
336

337
        /* If a unit is marked with RemainAfterElapse=yes we leave it
338
         * around even after it elapsed once, so that starting it
339
         * later again does not necessarily mean immediate
340
         * retriggering. We unconditionally leave units with
341
         * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
342
         * since they might be restarted automatically at any time
343
         * later on. */
344

345
        if (t->remain_after_elapse || leave_around)
2✔
346
                timer_set_state(t, TIMER_ELAPSED);
2✔
347
        else
348
                timer_enter_dead(t, TIMER_SUCCESS);
×
349
}
2✔
350

351
static void add_random_delay(Timer *t, usec_t *v) {
896✔
352
        usec_t add;
896✔
353

354
        assert(t);
896✔
355
        assert(v);
896✔
356

357
        if (t->random_delay_usec == 0)
896✔
358
                return;
359
        if (*v == USEC_INFINITY)
191✔
360
                return;
361

362
        add = (t->fixed_random_delay ? timer_get_fixed_delay_hash(t) : random_u64()) % t->random_delay_usec;
382✔
363

364
        if (*v + add < *v) /* overflow */
191✔
365
                *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
×
366
        else
367
                *v += add;
191✔
368

369
        log_unit_debug(UNIT(t), "Adding %s random time.", FORMAT_TIMESPAN(add, 0));
191✔
370
}
371

372
static void timer_enter_waiting(Timer *t, bool time_change) {
895✔
373
        bool found_monotonic = false, found_realtime = false;
895✔
374
        bool leave_around = false;
895✔
375
        triple_timestamp ts;
895✔
376
        Unit *trigger;
895✔
377
        int r;
895✔
378

379
        assert(t);
895✔
380

381
        trigger = UNIT_TRIGGER(UNIT(t));
895✔
382
        if (!trigger) {
895✔
383
                log_unit_error(UNIT(t), "Unit to trigger vanished.");
×
384
                goto fail;
×
385
        }
386

387
        triple_timestamp_now(&ts);
895✔
388
        t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
895✔
389

390
        LIST_FOREACH(value, v, t->values) {
2,291✔
391
                if (v->disabled)
1,396✔
392
                        continue;
12✔
393

394
                if (v->base == TIMER_CALENDAR) {
1,384✔
395
                        bool rebase_after_boot_time = false;
410✔
396
                        usec_t b, random_offset = 0;
410✔
397
                        usec_t boot_monotonic = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
410✔
398

399
                        if (t->random_offset_usec != 0)
410✔
400
                                random_offset = timer_get_fixed_delay_hash(t) % t->random_offset_usec;
×
401

402
                        /* If DeferReactivation= is enabled, schedule the job based on the last time
403
                         * the trigger unit entered inactivity. Otherwise, if we know the last time
404
                         * this was triggered, schedule the job based relative to that. If we don't,
405
                         * just start from the activation time or realtime.
406
                         *
407
                         * Unless we have a real last-trigger time, we subtract the random_offset because
408
                         * any event that elapsed within the last random_offset has actually been delayed
409
                         * and thus hasn't truly elapsed yet. */
410

411
                        if (t->defer_reactivation &&
410✔
412
                            dual_timestamp_is_set(&trigger->inactive_enter_timestamp)) {
3✔
413
                                if (dual_timestamp_is_set(&t->last_trigger))
2✔
414
                                        b = MAX(trigger->inactive_enter_timestamp.realtime,
2✔
415
                                                t->last_trigger.realtime);
416
                                else
417
                                        b = trigger->inactive_enter_timestamp.realtime;
418
                        } else if (dual_timestamp_is_set(&t->last_trigger)) {
408✔
419
                                b = t->last_trigger.realtime;
24✔
420

421
                                /* Check if the last_trigger timestamp is older than the current machine
422
                                 * boot. If so, this means the timestamp came from a stamp file of a
423
                                 * persistent timer and we need to rebase it to make RandomizedDelaySec=
424
                                 * work (see below). */
425
                                if (t->last_trigger.monotonic < boot_monotonic)
24✔
426
                                        rebase_after_boot_time = true;
22✔
427
                        } else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
384✔
428
                                b = UNIT(t)->inactive_exit_timestamp.realtime - random_offset;
322✔
429
                        else {
430
                                b = ts.realtime - random_offset;
62✔
431
                                rebase_after_boot_time = true;
62✔
432
                        }
433

434
                        r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
410✔
435
                        if (r < 0)
410✔
436
                                continue;
×
437

438
                        v->next_elapse += random_offset;
410✔
439

440
                        if (rebase_after_boot_time) {
410✔
441
                                /* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
442
                                 * time has already passed, set the time when systemd first started as the scheduled
443
                                 * time. Note that we base this on the monotonic timestamp of the boot, not the
444
                                 * realtime one, since the wallclock might have been off during boot. */
445
                                usec_t rebased = map_clock_usec(boot_monotonic, CLOCK_MONOTONIC, CLOCK_REALTIME);
84✔
446
                                if (v->next_elapse < rebased)
84✔
447
                                        v->next_elapse = rebased;
×
448
                        }
449

450
                        if (!found_realtime)
410✔
451
                                t->next_elapse_realtime = v->next_elapse;
410✔
452
                        else
453
                                t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
×
454

455
                        found_realtime = true;
456

457
                } else {
458
                        usec_t base;
974✔
459

460
                        switch (v->base) {
974✔
461

462
                        case TIMER_ACTIVE:
6✔
463
                                if (state_translation_table[t->state] == UNIT_ACTIVE)
6✔
464
                                        base = UNIT(t)->inactive_exit_timestamp.monotonic;
4✔
465
                                else
466
                                        base = ts.monotonic;
2✔
467
                                break;
468

469
                        case TIMER_BOOT:
194✔
470
                                if (detect_container() <= 0) {
194✔
471
                                        /* CLOCK_MONOTONIC equals the uptime on Linux */
472
                                        base = 0;
473
                                        break;
474
                                }
475
                                /* In a container we don't want to include the time the host
476
                                 * was already up when the container started, so count from
477
                                 * our own startup. */
478
                                _fallthrough_;
448✔
479
                        case TIMER_STARTUP:
480
                                base = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
448✔
481
                                break;
448✔
482

483
                        case TIMER_UNIT_ACTIVE:
485✔
484
                                leave_around = true;
485✔
485
                                base = MAX(trigger->inactive_exit_timestamp.monotonic, t->last_trigger.monotonic);
485✔
486
                                if (base <= 0)
485✔
487
                                        continue;
461✔
488
                                break;
489

490
                        case TIMER_UNIT_INACTIVE:
6✔
491
                                leave_around = true;
6✔
492
                                base = MAX(trigger->inactive_enter_timestamp.monotonic, t->last_trigger.monotonic);
6✔
493
                                if (base <= 0)
6✔
494
                                        continue;
4✔
495
                                break;
496

497
                        default:
×
498
                                assert_not_reached();
×
499
                        }
500

501
                        if (!time_change) {
509✔
502
                                bool is_oneshot = IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP);
495✔
503

504
                                /* Skip recalculating the next elapse timestamp for one-shot timers for which
505
                                 * we've already calculated the value in this activation cycle. */
506
                                if (!(v->next_elapse > 0 &&
513✔
507
                                      t->last_trigger.monotonic > base &&
43✔
508
                                      is_oneshot))
509
                                        v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
1,431✔
510

511
                                if (dual_timestamp_is_set(&t->last_trigger) &&
539✔
512
                                    v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
100✔
513
                                    is_oneshot) {
514
                                        /* This is a one time trigger, disable it now. */
515
                                        v->disabled = true;
12✔
516
                                        continue;
12✔
517
                                }
518
                        }
519

520
                        if (!found_monotonic)
497✔
521
                                t->next_elapse_monotonic_or_boottime = v->next_elapse;
486✔
522
                        else
523
                                t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
11✔
524

525
                        found_monotonic = true;
526
                }
527
        }
528

529
        if (!found_monotonic && !found_realtime && !t->on_timezone_change && !t->on_clock_change) {
895✔
530
                log_unit_debug(UNIT(t), "Timer is elapsed.");
2✔
531
                timer_enter_elapsed(t, leave_around);
2✔
532
                return;
897✔
533
        }
534

535
        if (found_monotonic) {
893✔
536
                usec_t left;
486✔
537

538
                add_random_delay(t, &t->next_elapse_monotonic_or_boottime);
486✔
539

540
                left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
972✔
541
                log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", FORMAT_TIMESPAN(left, 0));
486✔
542

543
                if (t->monotonic_event_source) {
486✔
544
                        r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
38✔
545
                        if (r < 0) {
38✔
546
                                log_unit_warning_errno(UNIT(t), r, "Failed to reschedule monotonic event source: %m");
×
UNCOV
547
                                goto fail;
×
548
                        }
549

550
                        r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
38✔
551
                        if (r < 0) {
38✔
UNCOV
552
                                log_unit_warning_errno(UNIT(t), r, "Failed to enable monotonic event source: %m");
×
UNCOV
553
                                goto fail;
×
554
                        }
555
                } else {
556
                        r = sd_event_add_time(
1,792✔
557
                                        UNIT(t)->manager->event,
448✔
558
                                        &t->monotonic_event_source,
559
                                        t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
448✔
560
                                        t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
448✔
561
                                        timer_dispatch, t);
562
                        if (r < 0) {
448✔
UNCOV
563
                                log_unit_warning_errno(UNIT(t), r, "Failed to add monotonic event source: %m");
×
UNCOV
564
                                goto fail;
×
565
                        }
566

567
                        (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
448✔
568
                }
569

570
        } else {
571
                r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
407✔
572
                if (r < 0) {
407✔
UNCOV
573
                        log_unit_warning_errno(UNIT(t), r, "Failed to disable monotonic event source: %m");
×
UNCOV
574
                        goto fail;
×
575
                }
576
        }
577

578
        if (found_realtime) {
893✔
579
                add_random_delay(t, &t->next_elapse_realtime);
410✔
580

581
                log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", FORMAT_TIMESTAMP(t->next_elapse_realtime));
410✔
582

583
                if (t->realtime_event_source) {
410✔
584
                        r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
1✔
585
                        if (r < 0) {
1✔
586
                                log_unit_warning_errno(UNIT(t), r, "Failed to reschedule realtime event source: %m");
×
UNCOV
587
                                goto fail;
×
588
                        }
589

590
                        r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
1✔
591
                        if (r < 0) {
1✔
UNCOV
592
                                log_unit_warning_errno(UNIT(t), r, "Failed to enable realtime event source: %m");
×
UNCOV
593
                                goto fail;
×
594
                        }
595
                } else {
596
                        r = sd_event_add_time(
1,636✔
597
                                        UNIT(t)->manager->event,
409✔
598
                                        &t->realtime_event_source,
599
                                        t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
409✔
600
                                        t->next_elapse_realtime, t->accuracy_usec,
409✔
601
                                        timer_dispatch, t);
602
                        if (r < 0) {
409✔
UNCOV
603
                                log_unit_warning_errno(UNIT(t), r, "Failed to add realtime event source: %m");
×
UNCOV
604
                                goto fail;
×
605
                        }
606

607
                        (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
409✔
608
                }
609

610
        } else if (t->realtime_event_source) {
483✔
611

UNCOV
612
                r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
×
UNCOV
613
                if (r < 0) {
×
UNCOV
614
                        log_unit_warning_errno(UNIT(t), r, "Failed to disable realtime event source: %m");
×
615
                        goto fail;
×
616
                }
617
        }
618

619
        timer_set_state(t, TIMER_WAITING);
893✔
620
        return;
621

UNCOV
622
fail:
×
UNCOV
623
        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
×
624
}
625

626
static void timer_enter_running(Timer *t) {
16✔
627
        _cleanup_(activation_details_unrefp) ActivationDetails *details = NULL;
16✔
628
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
16✔
629
        Unit *trigger;
16✔
630
        Job *job;
16✔
631
        int r;
16✔
632

633
        assert(t);
16✔
634

635
        /* Don't start job if we are supposed to go down */
636
        if (unit_stop_pending(UNIT(t)))
16✔
637
                return;
638

639
        trigger = UNIT_TRIGGER(UNIT(t));
16✔
640
        if (!trigger) {
16✔
641
                log_unit_error(UNIT(t), "Unit to trigger vanished.");
×
UNCOV
642
                goto fail;
×
643
        }
644

645
        details = activation_details_new(UNIT(t));
16✔
646
        if (!details) {
16✔
647
                log_oom();
×
UNCOV
648
                goto fail;
×
649
        }
650

651
        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, &job);
16✔
652
        if (r < 0) {
16✔
UNCOV
653
                log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
×
UNCOV
654
                goto fail;
×
655
        }
656

657
        dual_timestamp_now(&t->last_trigger);
16✔
658
        ACTIVATION_DETAILS_TIMER(details)->last_trigger = t->last_trigger;
16✔
659

660
        job_set_activation_details(job, details);
16✔
661

662
        if (t->stamp_path)
16✔
UNCOV
663
                touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
×
664

665
        timer_set_state(t, TIMER_RUNNING);
16✔
666
        return;
667

UNCOV
668
fail:
×
UNCOV
669
        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
×
670
}
671

672
static int timer_start(Unit *u) {
328✔
673
        Timer *t = ASSERT_PTR(TIMER(u));
328✔
674
        int r;
328✔
675

676
        assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
328✔
677

678
        r = unit_acquire_invocation_id(u);
328✔
679
        if (r < 0)
328✔
680
                return r;
681

682
        /* Reenable all timers that depend on unit activation time */
683
        LIST_FOREACH(value, v, t->values)
903✔
684
                if (v->base == TIMER_ACTIVE)
575✔
685
                        v->disabled = false;
2✔
686

687
        if (t->stamp_path) {
328✔
688
                struct stat st;
84✔
689

690
                if (stat(t->stamp_path, &st) >= 0) {
84✔
691
                        usec_t ft;
18✔
692

693
                        /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
694
                         * something is wrong with the system clock. */
695

696
                        ft = timespec_load(&st.st_mtim);
18✔
697
                        if (ft < now(CLOCK_REALTIME))
18✔
698
                                t->last_trigger.realtime = ft;
18✔
699
                        else
UNCOV
700
                                log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
×
701
                                                 FORMAT_TIMESTAMP(ft));
702

703
                } else if (errno == ENOENT)
66✔
704
                        /* The timer has never run before, make sure a stamp file exists. */
705
                        (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
66✔
706
        }
707

708
        t->result = TIMER_SUCCESS;
328✔
709
        timer_enter_waiting(t, false);
328✔
710
        return 1;
328✔
711
}
712

713
static int timer_stop(Unit *u) {
289✔
714
        Timer *t = ASSERT_PTR(TIMER(u));
289✔
715

716
        assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
289✔
717

718
        timer_enter_dead(t, TIMER_SUCCESS);
289✔
719
        return 1;
289✔
720
}
721

722
static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
599✔
723
        Timer *t = ASSERT_PTR(TIMER(u));
599✔
724

725
        assert(f);
599✔
726
        assert(fds);
599✔
727

728
        (void) serialize_item(f, "state", timer_state_to_string(t->state));
599✔
729
        (void) serialize_item(f, "result", timer_result_to_string(t->result));
599✔
730

731
        if (dual_timestamp_is_set(&t->last_trigger))
599✔
732
                (void) serialize_usec(f, "last-trigger-realtime", t->last_trigger.realtime);
8✔
733

734
        if (t->last_trigger.monotonic > 0)
599✔
735
                (void) serialize_usec(f, "last-trigger-monotonic", t->last_trigger.monotonic);
2✔
736

737
        return 0;
599✔
738
}
739

740
static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
1,076✔
741
        Timer *t = ASSERT_PTR(TIMER(u));
1,076✔
742

743
        assert(key);
1,076✔
744
        assert(value);
1,076✔
745
        assert(fds);
1,076✔
746

747
        if (streq(key, "state")) {
1,076✔
748
                TimerState state;
534✔
749

750
                state = timer_state_from_string(value);
534✔
751
                if (state < 0)
534✔
UNCOV
752
                        log_unit_debug(u, "Failed to parse state value: %s", value);
×
753
                else
754
                        t->deserialized_state = state;
534✔
755

756
        } else if (streq(key, "result")) {
542✔
757
                TimerResult f;
534✔
758

759
                f = timer_result_from_string(value);
534✔
760
                if (f < 0)
534✔
UNCOV
761
                        log_unit_debug(u, "Failed to parse result value: %s", value);
×
762
                else if (f != TIMER_SUCCESS)
534✔
763
                        t->result = f;
×
764

765
        } else if (streq(key, "last-trigger-realtime"))
8✔
766
                (void) deserialize_usec(value, &t->last_trigger.realtime);
6✔
767
        else if (streq(key, "last-trigger-monotonic"))
2✔
768
                (void) deserialize_usec(value, &t->last_trigger.monotonic);
2✔
769
        else
UNCOV
770
                log_unit_debug(u, "Unknown serialization key: %s", key);
×
771

772
        return 0;
1,076✔
773
}
774

775
static UnitActiveState timer_active_state(Unit *u) {
21,063✔
776
        Timer *t = ASSERT_PTR(TIMER(u));
21,063✔
777

778
        return state_translation_table[t->state];
21,063✔
779
}
780

781
static const char *timer_sub_state_to_string(Unit *u) {
649✔
782
        Timer *t = ASSERT_PTR(TIMER(u));
649✔
783

784
        return timer_state_to_string(t->state);
649✔
785
}
786

787
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
16✔
788
        Timer *t = ASSERT_PTR(TIMER(userdata));
16✔
789

790
        if (t->state != TIMER_WAITING)
16✔
791
                return 0;
792

793
        log_unit_debug(UNIT(t), "Timer elapsed.");
16✔
794
        timer_enter_running(t);
16✔
795
        return 0;
16✔
796
}
797

798
static void timer_trigger_notify(Unit *u, Unit *other) {
49✔
799
        Timer *t = ASSERT_PTR(TIMER(u));
49✔
800

801
        assert(other);
49✔
802

803
        /* Filter out invocations with bogus state */
804
        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
49✔
805

806
        /* Reenable all timers that depend on unit state */
807
        LIST_FOREACH(value, v, t->values)
165✔
808
                if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
116✔
809
                        v->disabled = false;
47✔
810

811
        switch (t->state) {
49✔
812

813
        case TIMER_WAITING:
13✔
814
        case TIMER_ELAPSED:
815

816
                /* Recalculate sleep time */
817
                timer_enter_waiting(t, false);
13✔
818
                break;
13✔
819

820
        case TIMER_RUNNING:
36✔
821

822
                if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
36✔
823
                        log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
14✔
824
                        timer_enter_waiting(t, false);
14✔
825
                }
826
                break;
827

828
        case TIMER_DEAD:
829
        case TIMER_FAILED:
830
                break;
831

UNCOV
832
        default:
×
UNCOV
833
                assert_not_reached();
×
834
        }
835
}
49✔
836

837
static void timer_reset_failed(Unit *u) {
12✔
838
        Timer *t = ASSERT_PTR(TIMER(u));
12✔
839

840
        if (t->state == TIMER_FAILED)
12✔
UNCOV
841
                timer_set_state(t, TIMER_DEAD);
×
842

843
        t->result = TIMER_SUCCESS;
12✔
844
}
12✔
845

846
static void timer_time_change(Unit *u) {
14✔
847
        Timer *t = ASSERT_PTR(TIMER(u));
14✔
848
        usec_t ts;
14✔
849

850
        if (t->state != TIMER_WAITING)
14✔
851
                return;
852

853
        /* If we appear to have triggered in the future, the system clock must
854
         * have been set backwards.  So let's rewind our own clock and allow
855
         * the future triggers to happen again :).  Exactly the same as when
856
         * you start a timer unit with Persistent=yes. */
857
        ts = now(CLOCK_REALTIME);
14✔
858
        if (t->last_trigger.realtime > ts)
14✔
UNCOV
859
                t->last_trigger.realtime = ts;
×
860

861
        if (t->on_clock_change) {
14✔
UNCOV
862
                log_unit_debug(u, "Time change, triggering activation.");
×
UNCOV
863
                timer_enter_running(t);
×
864
        } else {
865
                log_unit_debug(u, "Time change, recalculating next elapse.");
14✔
866
                timer_enter_waiting(t, true);
14✔
867
        }
868
}
869

870
static void timer_timezone_change(Unit *u) {
79✔
871
        Timer *t = ASSERT_PTR(TIMER(u));
79✔
872

873
        if (t->state != TIMER_WAITING)
79✔
874
                return;
875

876
        if (t->on_timezone_change) {
12✔
UNCOV
877
                log_unit_debug(u, "Timezone change, triggering activation.");
×
878
                timer_enter_running(t);
×
879
        } else {
880
                log_unit_debug(u, "Timezone change, recalculating next elapse.");
12✔
881
                timer_enter_waiting(t, false);
12✔
882
        }
883
}
884

UNCOV
885
static int timer_clean(Unit *u, ExecCleanMask mask) {
×
UNCOV
886
        Timer *t = ASSERT_PTR(TIMER(u));
×
887
        int r;
×
888

UNCOV
889
        assert(mask != 0);
×
890

891
        if (t->state != TIMER_DEAD)
×
892
                return -EBUSY;
893

894
        if (mask != EXEC_CLEAN_STATE)
×
895
                return -EUNATCH;
896

897
        r = timer_setup_persistent(t);
×
898
        if (r < 0)
×
899
                return r;
900

UNCOV
901
        if (!t->stamp_path)
×
902
                return -EUNATCH;
903

UNCOV
904
        if (unlink(t->stamp_path) && errno != ENOENT)
×
UNCOV
905
                return log_unit_error_errno(u, errno, "Failed to clean stamp file of timer: %m");
×
906

907
        return 0;
908
}
909

910
static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
38✔
911
        Timer *t = ASSERT_PTR(TIMER(u));
38✔
912

913
        assert(ret);
38✔
914

915
        *ret = t->persistent ? EXEC_CLEAN_STATE : 0;
38✔
916
        return 0;
38✔
917
}
918

919
static int timer_test_startable(Unit *u) {
328✔
920
        Timer *t = ASSERT_PTR(TIMER(u));
328✔
921
        int r;
328✔
922

923
        r = unit_test_trigger_loaded(u);
328✔
924
        if (r < 0)
328✔
925
                return r;
926

927
        r = unit_test_start_limit(u);
328✔
928
        if (r < 0) {
328✔
UNCOV
929
                timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
×
UNCOV
930
                return r;
×
931
        }
932

933
        return true;
934
}
935

936
static void activation_details_timer_serialize(const ActivationDetails *details, FILE *f) {
2✔
937
        const ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
2✔
938

939
        assert(f);
2✔
940
        assert(t);
2✔
941

942
        (void) serialize_dual_timestamp(f, "activation-details-timer-last-trigger", &t->last_trigger);
2✔
943
}
2✔
944

945
static int activation_details_timer_deserialize(const char *key, const char *value, ActivationDetails **details) {
2✔
946
        int r;
2✔
947

948
        assert(key);
2✔
949
        assert(value);
2✔
950
        POINTER_MAY_BE_NULL(details);
2✔
951

952
        if (!details || !*details)
2✔
953
                return -EINVAL;
954

955
        ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(*details);
2✔
956
        if (!t)
2✔
957
                return -EINVAL;
958

959
        if (!streq(key, "activation-details-timer-last-trigger"))
2✔
960
                return -EINVAL;
961

962
        r = deserialize_dual_timestamp(value, &t->last_trigger);
2✔
963
        if (r < 0)
2✔
UNCOV
964
                return r;
×
965

966
        return 0;
967
}
968

969
static int activation_details_timer_append_env(const ActivationDetails *details, char ***strv) {
16✔
970
        const ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
16✔
971
        int r;
16✔
972

973
        assert(strv);
16✔
974
        assert(t);
16✔
975

976
        if (!dual_timestamp_is_set(&t->last_trigger))
16✔
977
                return 0;
978

979
        r = strv_extendf(strv, "TRIGGER_TIMER_REALTIME_USEC=" USEC_FMT, t->last_trigger.realtime);
16✔
980
        if (r < 0)
16✔
981
                return r;
982

983
        r = strv_extendf(strv, "TRIGGER_TIMER_MONOTONIC_USEC=" USEC_FMT, t->last_trigger.monotonic);
16✔
984
        if (r < 0)
16✔
UNCOV
985
                return r;
×
986

987
        return 2; /* Return the number of variables added to the env block */
988
}
989

990
static int activation_details_timer_append_pair(const ActivationDetails *details, char ***strv) {
40✔
991
        const ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
40✔
992
        int r;
40✔
993

994
        assert(strv);
40✔
995
        assert(t);
40✔
996

997
        if (!dual_timestamp_is_set(&t->last_trigger))
40✔
998
                return 0;
999

1000
        r = strv_extend(strv, "trigger_timer_realtime_usec");
40✔
1001
        if (r < 0)
40✔
1002
                return r;
1003

1004
        r = strv_extendf(strv, USEC_FMT, t->last_trigger.realtime);
40✔
1005
        if (r < 0)
40✔
1006
                return r;
1007

1008
        r = strv_extend(strv, "trigger_timer_monotonic_usec");
40✔
1009
        if (r < 0)
40✔
1010
                return r;
1011

1012
        r = strv_extendf(strv, USEC_FMT, t->last_trigger.monotonic);
40✔
1013
        if (r < 0)
40✔
UNCOV
1014
                return r;
×
1015

1016
        return 2; /* Return the number of pairs added to the env block */
1017
}
1018

1019
uint64_t timer_next_elapse_monotonic(const Timer *t) {
605✔
1020
        assert(t);
605✔
1021

1022
        return (uint64_t) usec_shift_clock(t->next_elapse_monotonic_or_boottime,
605✔
1023
                                           TIMER_MONOTONIC_CLOCK(t), CLOCK_MONOTONIC);
605✔
1024
}
1025

1026
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
1027
        [TIMER_ACTIVE]        = "OnActiveSec",
1028
        [TIMER_BOOT]          = "OnBootSec",
1029
        [TIMER_STARTUP]       = "OnStartupSec",
1030
        [TIMER_UNIT_ACTIVE]   = "OnUnitActiveSec",
1031
        [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
1032
        [TIMER_CALENDAR]      = "OnCalendar",
1033
};
1034

1035
DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
146✔
1036

1037
char* timer_base_to_usec_string(TimerBase i) {
56✔
1038
        _cleanup_free_ char *buf = NULL;
112✔
1039
        const char *s;
56✔
1040
        size_t l;
56✔
1041

1042
        s = timer_base_to_string(i);
56✔
1043

1044
        if (endswith(s, "Sec")) {
56✔
1045
                /* s/Sec/USec/ */
1046
                l = strlen(s);
35✔
1047
                buf = new(char, l+2);
35✔
1048
                if (!buf)
35✔
1049
                        return NULL;
1050

1051
                memcpy(buf, s, l-3);
35✔
1052
                memcpy(buf+l-3, "USec", 5);
35✔
1053
        } else {
1054
                buf = strdup(s);
21✔
1055
                if (!buf)
21✔
UNCOV
1056
                        return NULL;
×
1057
        }
1058

1059
        return TAKE_PTR(buf);
1060
}
1061

1062
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
1063
        [TIMER_SUCCESS]                 = "success",
1064
        [TIMER_FAILURE_RESOURCES]       = "resources",
1065
        [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
1066
};
1067

1068
DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
2,089✔
1069

1070
const UnitVTable timer_vtable = {
1071
        .object_size = sizeof(Timer),
1072

1073
        .sections =
1074
                "Unit\0"
1075
                "Timer\0"
1076
                "Install\0",
1077
        .private_section = "Timer",
1078

1079
        .can_transient = true,
1080
        .can_fail = true,
1081
        .can_trigger = true,
1082

1083
        .init = timer_init,
1084
        .done = timer_done,
1085
        .load = timer_load,
1086

1087
        .coldplug = timer_coldplug,
1088

1089
        .dump = timer_dump,
1090

1091
        .start = timer_start,
1092
        .stop = timer_stop,
1093

1094
        .clean = timer_clean,
1095
        .can_clean = timer_can_clean,
1096

1097
        .serialize = timer_serialize,
1098
        .deserialize_item = timer_deserialize_item,
1099

1100
        .active_state = timer_active_state,
1101
        .sub_state_to_string = timer_sub_state_to_string,
1102

1103
        .trigger_notify = timer_trigger_notify,
1104

1105
        .reset_failed = timer_reset_failed,
1106
        .time_change = timer_time_change,
1107
        .timezone_change = timer_timezone_change,
1108

1109
        .bus_set_property = bus_timer_set_property,
1110

1111
        .test_startable = timer_test_startable,
1112
};
1113

1114
const ActivationDetailsVTable activation_details_timer_vtable = {
1115
        .object_size = sizeof(ActivationDetailsTimer),
1116

1117
        .serialize = activation_details_timer_serialize,
1118
        .deserialize = activation_details_timer_deserialize,
1119
        .append_env = activation_details_timer_append_env,
1120
        .append_pair = activation_details_timer_append_pair,
1121
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc