]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/timer.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / timer.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
a7334b09 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
d46de8a1
LP
21#include <errno.h>
22
b5efdb8a 23#include "alloc-util.h"
07630cea
LP
24#include "bus-error.h"
25#include "bus-util.h"
871d7de4 26#include "dbus-timer.h"
f4f15635 27#include "fs-util.h"
6bedfcbb 28#include "parse-util.h"
744c7693 29#include "random-util.h"
a40eb732 30#include "special.h"
8b43440b 31#include "string-table.h"
07630cea 32#include "string-util.h"
b1d4f8e1 33#include "timer.h"
07630cea
LP
34#include "unit-name.h"
35#include "unit.h"
b1d4f8e1 36#include "user-util.h"
c1d9ba99 37#include "virt.h"
871d7de4
LP
38
39static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
40 [TIMER_DEAD] = UNIT_INACTIVE,
41 [TIMER_WAITING] = UNIT_ACTIVE,
42 [TIMER_RUNNING] = UNIT_ACTIVE,
43 [TIMER_ELAPSED] = UNIT_ACTIVE,
fdf20a31 44 [TIMER_FAILED] = UNIT_FAILED
871d7de4
LP
45};
46
718db961
LP
47static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
48
871d7de4
LP
49static void timer_init(Unit *u) {
50 Timer *t = TIMER(u);
51
52 assert(u);
ac155bb8 53 assert(u->load_state == UNIT_STUB);
871d7de4 54
3a43da28
KS
55 t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
56 t->next_elapse_realtime = USEC_INFINITY;
bd8f585b 57 t->accuracy_usec = u->manager->default_timer_accuracy_usec;
3e0c30ac 58 t->remain_after_elapse = true;
871d7de4 59}
5cb5a6ff 60
74051b9b 61void timer_free_values(Timer *t) {
871d7de4
LP
62 TimerValue *v;
63
64 assert(t);
65
66 while ((v = t->values)) {
71fda00f 67 LIST_REMOVE(value, t->values, v);
3e044c49 68 calendar_spec_free(v->calendar_spec);
871d7de4
LP
69 free(v);
70 }
74051b9b
LP
71}
72
73static void timer_done(Unit *u) {
74 Timer *t = TIMER(u);
75
76 assert(t);
77
78 timer_free_values(t);
871d7de4 79
718db961
LP
80 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
81 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
06642d17
LP
82
83 free(t->stamp_path);
871d7de4
LP
84}
85
86static int timer_verify(Timer *t) {
87 assert(t);
88
1124fe6f 89 if (UNIT(t)->load_state != UNIT_LOADED)
871d7de4
LP
90 return 0;
91
92 if (!t->values) {
f2341e0a 93 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
871d7de4
LP
94 return -EINVAL;
95 }
96
97 return 0;
98}
99
6c155fe3
LP
100static int timer_add_default_dependencies(Timer *t) {
101 int r;
19f8d037 102 TimerValue *v;
6c155fe3
LP
103
104 assert(t);
105
4c9ea260
LP
106 if (!UNIT(t)->default_dependencies)
107 return 0;
108
eef85c4a 109 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
e3d84721
LP
110 if (r < 0)
111 return r;
2a77d31d 112
463d0d15 113 if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
eef85c4a 114 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
36697dc0 115 if (r < 0)
6c155fe3 116 return r;
19f8d037
TGR
117
118 LIST_FOREACH(value, v, t->values) {
119 if (v->base == TIMER_CALENDAR) {
eef85c4a 120 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
19f8d037
TGR
121 if (r < 0)
122 return r;
123 break;
124 }
125 }
2a77d31d 126 }
6c155fe3 127
eef85c4a
LP
128 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
129}
130
131static int timer_add_trigger_dependencies(Timer *t) {
132 Unit *x;
133 int r;
134
135 assert(t);
136
137 if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS]))
138 return 0;
139
140 r = unit_load_related_unit(UNIT(t), ".service", &x);
141 if (r < 0)
142 return r;
143
144 return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
6c155fe3
LP
145}
146
06642d17
LP
147static int timer_setup_persistent(Timer *t) {
148 int r;
149
150 assert(t);
151
152 if (!t->persistent)
153 return 0;
154
463d0d15 155 if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
06642d17 156
eef85c4a 157 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE);
06642d17
LP
158 if (r < 0)
159 return r;
160
161 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
162 } else {
163 const char *e;
164
165 e = getenv("XDG_DATA_HOME");
166 if (e)
605405c6 167 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id);
06642d17
LP
168 else {
169
170 _cleanup_free_ char *h = NULL;
171
172 r = get_home_dir(&h);
23bbb0de 173 if (r < 0)
f2341e0a 174 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
06642d17 175
605405c6 176 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id);
06642d17
LP
177 }
178 }
179
180 if (!t->stamp_path)
181 return log_oom();
182
183 return 0;
184}
185
871d7de4
LP
186static int timer_load(Unit *u) {
187 Timer *t = TIMER(u);
188 int r;
189
190 assert(u);
ac155bb8 191 assert(u->load_state == UNIT_STUB);
871d7de4 192
36697dc0
LP
193 r = unit_load_fragment_and_dropin(u);
194 if (r < 0)
871d7de4
LP
195 return r;
196
ac155bb8 197 if (u->load_state == UNIT_LOADED) {
871d7de4 198
eef85c4a
LP
199 r = timer_add_trigger_dependencies(t);
200 if (r < 0)
201 return r;
57020a3a 202
06642d17
LP
203 r = timer_setup_persistent(t);
204 if (r < 0)
205 return r;
206
4c9ea260
LP
207 r = timer_add_default_dependencies(t);
208 if (r < 0)
209 return r;
871d7de4
LP
210 }
211
212 return timer_verify(t);
213}
214
215static void timer_dump(Unit *u, FILE *f, const char *prefix) {
9f5eb56a 216 char buf[FORMAT_TIMESPAN_MAX];
871d7de4 217 Timer *t = TIMER(u);
3ecaa09b 218 Unit *trigger;
871d7de4 219 TimerValue *v;
034c6ed7 220
3ecaa09b
LP
221 trigger = UNIT_TRIGGER(u);
222
871d7de4
LP
223 fprintf(f,
224 "%sTimer State: %s\n"
067d72c9 225 "%sResult: %s\n"
9f5eb56a 226 "%sUnit: %s\n"
dedabea4
LP
227 "%sPersistent: %s\n"
228 "%sWakeSystem: %s\n"
3e0c30ac
LP
229 "%sAccuracy: %s\n"
230 "%sRemainAfterElapse: %s\n",
871d7de4 231 prefix, timer_state_to_string(t->state),
067d72c9 232 prefix, timer_result_to_string(t->result),
9f5eb56a 233 prefix, trigger ? trigger->id : "n/a",
dedabea4
LP
234 prefix, yes_no(t->persistent),
235 prefix, yes_no(t->wake_system),
3e0c30ac
LP
236 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
237 prefix, yes_no(t->remain_after_elapse));
871d7de4 238
36697dc0
LP
239 LIST_FOREACH(value, v, t->values) {
240
241 if (v->base == TIMER_CALENDAR) {
242 _cleanup_free_ char *p = NULL;
243
25cb94d4 244 (void) calendar_spec_to_string(v->calendar_spec, &p);
36697dc0
LP
245
246 fprintf(f,
247 "%s%s: %s\n",
248 prefix,
249 timer_base_to_string(v->base),
250 strna(p));
251 } else {
252 char timespan1[FORMAT_TIMESPAN_MAX];
253
254 fprintf(f,
255 "%s%s: %s\n",
256 prefix,
257 timer_base_to_string(v->base),
b1d6dcf5 258 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
36697dc0
LP
259 }
260 }
871d7de4
LP
261}
262
263static void timer_set_state(Timer *t, TimerState state) {
264 TimerState old_state;
034c6ed7 265 assert(t);
871d7de4
LP
266
267 old_state = t->state;
268 t->state = state;
269
36697dc0 270 if (state != TIMER_WAITING) {
718db961
LP
271 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
272 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
6e2c9ce1
ZJS
273 t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
274 t->next_elapse_realtime = USEC_INFINITY;
36697dc0 275 }
871d7de4
LP
276
277 if (state != old_state)
f2341e0a 278 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
871d7de4 279
e2f3b44c 280 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
871d7de4
LP
281}
282
283static void timer_enter_waiting(Timer *t, bool initial);
284
be847e82 285static int timer_coldplug(Unit *u) {
871d7de4
LP
286 Timer *t = TIMER(u);
287
288 assert(t);
289 assert(t->state == TIMER_DEAD);
290
3e0c30ac
LP
291 if (t->deserialized_state == t->state)
292 return 0;
871d7de4 293
3e0c30ac
LP
294 if (t->deserialized_state == TIMER_WAITING)
295 timer_enter_waiting(t, false);
296 else
297 timer_set_state(t, t->deserialized_state);
871d7de4
LP
298
299 return 0;
300}
301
067d72c9 302static void timer_enter_dead(Timer *t, TimerResult f) {
871d7de4
LP
303 assert(t);
304
a0fef983 305 if (t->result == TIMER_SUCCESS)
067d72c9 306 t->result = f;
871d7de4 307
ed77d407
LP
308 if (t->result != TIMER_SUCCESS)
309 log_unit_warning(UNIT(t), "Failed with result '%s'.", timer_result_to_string(t->result));
310
067d72c9 311 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
871d7de4
LP
312}
313
3e0c30ac
LP
314static void timer_enter_elapsed(Timer *t, bool leave_around) {
315 assert(t);
316
317 /* If a unit is marked with RemainAfterElapse=yes we leave it
318 * around even after it elapsed once, so that starting it
319 * later again does not necessarily mean immediate
320 * retriggering. We unconditionally leave units with
321 * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
322 * since they might be restarted automatically at any time
323 * later on. */
324
325 if (t->remain_after_elapse || leave_around)
326 timer_set_state(t, TIMER_ELAPSED);
327 else
328 timer_enter_dead(t, TIMER_SUCCESS);
329}
330
744c7693
LP
331static void add_random(Timer *t, usec_t *v) {
332 char s[FORMAT_TIMESPAN_MAX];
333 usec_t add;
334
335 assert(t);
3f51aec8 336 assert(v);
744c7693
LP
337
338 if (t->random_usec == 0)
339 return;
340 if (*v == USEC_INFINITY)
341 return;
342
343 add = random_u64() % t->random_usec;
344
345 if (*v + add < *v) /* overflow */
346 *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
347 else
348 *v += add;
349
382852fd 350 log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
744c7693
LP
351}
352
871d7de4 353static void timer_enter_waiting(Timer *t, bool initial) {
36697dc0 354 bool found_monotonic = false, found_realtime = false;
3e0c30ac 355 bool leave_around = false;
c54be90b
LP
356 triple_timestamp ts;
357 usec_t base = 0;
dedabea4 358 TimerValue *v;
e903182e 359 Unit *trigger;
871d7de4
LP
360 int r;
361
e903182e
LP
362 assert(t);
363
364 trigger = UNIT_TRIGGER(UNIT(t));
365 if (!trigger) {
366 log_unit_error(UNIT(t), "Unit to trigger vanished.");
367 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
368 return;
369 }
370
c54be90b 371 triple_timestamp_get(&ts);
dedabea4 372 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
871d7de4
LP
373
374 LIST_FOREACH(value, v, t->values) {
375
376 if (v->disabled)
377 continue;
378
36697dc0 379 if (v->base == TIMER_CALENDAR) {
06642d17
LP
380 usec_t b;
381
382 /* If we know the last time this was
383 * triggered, schedule the job based relative
384 * to that. If we don't just start from
385 * now. */
36697dc0 386
c54be90b 387 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts.realtime;
06642d17
LP
388
389 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
36697dc0
LP
390 if (r < 0)
391 continue;
392
36697dc0
LP
393 if (!found_realtime)
394 t->next_elapse_realtime = v->next_elapse;
10717a1a 395 else
36697dc0 396 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
871d7de4 397
36697dc0 398 found_realtime = true;
871d7de4 399
36697dc0 400 } else {
c54be90b 401
36697dc0 402 switch (v->base) {
871d7de4 403
36697dc0
LP
404 case TIMER_ACTIVE:
405 if (state_translation_table[t->state] == UNIT_ACTIVE)
406 base = UNIT(t)->inactive_exit_timestamp.monotonic;
407 else
c54be90b 408 base = ts.monotonic;
36697dc0 409 break;
871d7de4 410
36697dc0 411 case TIMER_BOOT:
c1d9ba99
MS
412 if (detect_container() <= 0) {
413 /* CLOCK_MONOTONIC equals the uptime on Linux */
414 base = 0;
415 break;
416 }
417 /* In a container we don't want to include the time the host
418 * was already up when the container started, so count from
ec251fe7
ZJS
419 * our own startup. */
420 /* fall through */
36697dc0
LP
421 case TIMER_STARTUP:
422 base = UNIT(t)->manager->userspace_timestamp.monotonic;
423 break;
871d7de4 424
36697dc0 425 case TIMER_UNIT_ACTIVE:
3e0c30ac 426 leave_around = true;
e903182e 427 base = trigger->inactive_exit_timestamp.monotonic;
e41e1943
LP
428
429 if (base <= 0)
06642d17 430 base = t->last_trigger.monotonic;
e41e1943
LP
431
432 if (base <= 0)
36697dc0 433 continue;
871d7de4 434
36697dc0 435 break;
871d7de4 436
36697dc0 437 case TIMER_UNIT_INACTIVE:
3e0c30ac 438 leave_around = true;
e903182e 439 base = trigger->inactive_enter_timestamp.monotonic;
e41e1943
LP
440
441 if (base <= 0)
06642d17 442 base = t->last_trigger.monotonic;
e41e1943
LP
443
444 if (base <= 0)
36697dc0 445 continue;
871d7de4 446
36697dc0 447 break;
871d7de4 448
36697dc0
LP
449 default:
450 assert_not_reached("Unknown timer base");
451 }
871d7de4 452
c54be90b 453 v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
36697dc0 454
c54be90b
LP
455 if (!initial &&
456 v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
457 IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
e41e1943 458 /* This is a one time trigger, disable it now */
36697dc0
LP
459 v->disabled = true;
460 continue;
461 }
462
463 if (!found_monotonic)
dedabea4 464 t->next_elapse_monotonic_or_boottime = v->next_elapse;
36697dc0 465 else
dedabea4 466 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
36697dc0
LP
467
468 found_monotonic = true;
469 }
871d7de4
LP
470 }
471
36697dc0 472 if (!found_monotonic && !found_realtime) {
f2341e0a 473 log_unit_debug(UNIT(t), "Timer is elapsed.");
3e0c30ac 474 timer_enter_elapsed(t, leave_around);
871d7de4
LP
475 return;
476 }
477
36697dc0
LP
478 if (found_monotonic) {
479 char buf[FORMAT_TIMESPAN_MAX];
3e0c30ac 480 usec_t left;
dedabea4 481
744c7693
LP
482 add_random(t, &t->next_elapse_monotonic_or_boottime);
483
c54be90b 484 left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
3e0c30ac 485 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
871d7de4 486
718db961 487 if (t->monotonic_event_source) {
dedabea4 488 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
718db961
LP
489 if (r < 0)
490 goto fail;
491
492 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
cbf60d0a
LP
493 if (r < 0)
494 goto fail;
495 } else {
496
6a0f1f6d
LP
497 r = sd_event_add_time(
498 UNIT(t)->manager->event,
499 &t->monotonic_event_source,
dedabea4
LP
500 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
501 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
6a0f1f6d 502 timer_dispatch, t);
cbf60d0a
LP
503 if (r < 0)
504 goto fail;
718db961 505
cbf60d0a
LP
506 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
507 }
7dfbe2e3 508
718db961 509 } else if (t->monotonic_event_source) {
718db961 510
06642d17 511 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
718db961
LP
512 if (r < 0)
513 goto fail;
514 }
36697dc0
LP
515
516 if (found_realtime) {
517 char buf[FORMAT_TIMESTAMP_MAX];
744c7693
LP
518
519 add_random(t, &t->next_elapse_realtime);
520
f2341e0a 521 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
36697dc0 522
718db961
LP
523 if (t->realtime_event_source) {
524 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
525 if (r < 0)
526 goto fail;
527
528 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
cbf60d0a
LP
529 if (r < 0)
530 goto fail;
531 } else {
6a0f1f6d
LP
532 r = sd_event_add_time(
533 UNIT(t)->manager->event,
534 &t->realtime_event_source,
dedabea4 535 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
6a0f1f6d
LP
536 t->next_elapse_realtime, t->accuracy_usec,
537 timer_dispatch, t);
cbf60d0a
LP
538 if (r < 0)
539 goto fail;
718db961 540
cbf60d0a
LP
541 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
542 }
7dfbe2e3 543
718db961 544 } else if (t->realtime_event_source) {
718db961 545
06642d17 546 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
718db961
LP
547 if (r < 0)
548 goto fail;
549 }
871d7de4
LP
550
551 timer_set_state(t, TIMER_WAITING);
552 return;
553
554fail:
f2341e0a 555 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
067d72c9 556 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
557}
558
559static void timer_enter_running(Timer *t) {
4afd3348 560 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e903182e 561 Unit *trigger;
871d7de4 562 int r;
398ef8ba 563
871d7de4
LP
564 assert(t);
565
ba3e67a7 566 /* Don't start job if we are supposed to go down */
31afa0a4 567 if (unit_stop_pending(UNIT(t)))
ba3e67a7
LP
568 return;
569
e903182e
LP
570 trigger = UNIT_TRIGGER(UNIT(t));
571 if (!trigger) {
572 log_unit_error(UNIT(t), "Unit to trigger vanished.");
573 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
574 return;
575 }
576
577 r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
36697dc0 578 if (r < 0)
871d7de4
LP
579 goto fail;
580
06642d17
LP
581 dual_timestamp_get(&t->last_trigger);
582
472fc28f 583 if (t->stamp_path)
ee735086 584 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
e41e1943 585
871d7de4
LP
586 timer_set_state(t, TIMER_RUNNING);
587 return;
588
589fail:
f2341e0a 590 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
067d72c9 591 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
592}
593
594static int timer_start(Unit *u) {
595 Timer *t = TIMER(u);
779042e7 596 TimerValue *v;
e903182e 597 Unit *trigger;
07299350 598 int r;
871d7de4
LP
599
600 assert(t);
3742095b 601 assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
01f78473 602
e903182e
LP
603 trigger = UNIT_TRIGGER(u);
604 if (!trigger || trigger->load_state != UNIT_LOADED) {
605 log_unit_error(u, "Refusing to start, unit to trigger not loaded.");
01f78473 606 return -ENOENT;
e903182e 607 }
871d7de4 608
07299350
LP
609 r = unit_start_limit_test(u);
610 if (r < 0) {
611 timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
612 return r;
613 }
614
4b58153d
LP
615 r = unit_acquire_invocation_id(u);
616 if (r < 0)
617 return r;
618
06642d17
LP
619 t->last_trigger = DUAL_TIMESTAMP_NULL;
620
779042e7
MC
621 /* Reenable all timers that depend on unit activation time */
622 LIST_FOREACH(value, v, t->values)
623 if (v->base == TIMER_ACTIVE)
624 v->disabled = false;
625
06642d17
LP
626 if (t->stamp_path) {
627 struct stat st;
628
77542a79
LP
629 if (stat(t->stamp_path, &st) >= 0) {
630 usec_t ft;
631
632 /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
633 * something is wrong with the system clock. */
634
635 ft = timespec_load(&st.st_mtim);
636 if (ft < now(CLOCK_REALTIME))
637 t->last_trigger.realtime = ft;
638 else {
639 char z[FORMAT_TIMESTAMP_MAX];
640
641 log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
642 format_timestamp(z, sizeof(z), ft));
643 }
644
645 } else if (errno == ENOENT)
472fc28f
TB
646 /* The timer has never run before,
647 * make sure a stamp file exists.
648 */
4b58153d 649 (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
06642d17
LP
650 }
651
067d72c9 652 t->result = TIMER_SUCCESS;
871d7de4 653 timer_enter_waiting(t, true);
82a2b6bb 654 return 1;
871d7de4
LP
655}
656
657static int timer_stop(Unit *u) {
658 Timer *t = TIMER(u);
659
660 assert(t);
3742095b 661 assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
871d7de4 662
067d72c9 663 timer_enter_dead(t, TIMER_SUCCESS);
82a2b6bb 664 return 1;
871d7de4
LP
665}
666
667static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
668 Timer *t = TIMER(u);
669
670 assert(u);
671 assert(f);
672 assert(fds);
673
674 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
067d72c9 675 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
871d7de4 676
06642d17
LP
677 if (t->last_trigger.realtime > 0)
678 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
679
680 if (t->last_trigger.monotonic > 0)
681 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
682
871d7de4
LP
683 return 0;
684}
685
686static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
687 Timer *t = TIMER(u);
06642d17 688 int r;
871d7de4
LP
689
690 assert(u);
691 assert(key);
692 assert(value);
693 assert(fds);
694
695 if (streq(key, "state")) {
696 TimerState state;
697
36697dc0
LP
698 state = timer_state_from_string(value);
699 if (state < 0)
f2341e0a 700 log_unit_debug(u, "Failed to parse state value: %s", value);
871d7de4
LP
701 else
702 t->deserialized_state = state;
067d72c9
LP
703 } else if (streq(key, "result")) {
704 TimerResult f;
705
706 f = timer_result_from_string(value);
707 if (f < 0)
f2341e0a 708 log_unit_debug(u, "Failed to parse result value: %s", value);
067d72c9
LP
709 else if (f != TIMER_SUCCESS)
710 t->result = f;
06642d17
LP
711 } else if (streq(key, "last-trigger-realtime")) {
712
713 r = safe_atou64(value, &t->last_trigger.realtime);
714 if (r < 0)
f2341e0a 715 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
06642d17
LP
716
717 } else if (streq(key, "last-trigger-monotonic")) {
718
719 r = safe_atou64(value, &t->last_trigger.monotonic);
720 if (r < 0)
f2341e0a 721 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
067d72c9 722
871d7de4 723 } else
f2341e0a 724 log_unit_debug(u, "Unknown serialization key: %s", key);
871d7de4
LP
725
726 return 0;
034c6ed7
LP
727}
728
44a6b1b6 729_pure_ static UnitActiveState timer_active_state(Unit *u) {
871d7de4
LP
730 assert(u);
731
732 return state_translation_table[TIMER(u)->state];
733}
734
44a6b1b6 735_pure_ static const char *timer_sub_state_to_string(Unit *u) {
871d7de4
LP
736 assert(u);
737
738 return timer_state_to_string(TIMER(u)->state);
739}
740
718db961
LP
741static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
742 Timer *t = TIMER(userdata);
871d7de4
LP
743
744 assert(t);
5cb5a6ff 745
871d7de4 746 if (t->state != TIMER_WAITING)
718db961 747 return 0;
5cb5a6ff 748
f2341e0a 749 log_unit_debug(UNIT(t), "Timer elapsed.");
871d7de4 750 timer_enter_running(t);
718db961 751 return 0;
5cb5a6ff
LP
752}
753
3ecaa09b
LP
754static void timer_trigger_notify(Unit *u, Unit *other) {
755 Timer *t = TIMER(u);
756 TimerValue *v;
871d7de4 757
3ecaa09b
LP
758 assert(u);
759 assert(other);
871d7de4 760
3ecaa09b
LP
761 if (other->load_state != UNIT_LOADED)
762 return;
871d7de4 763
3ecaa09b
LP
764 /* Reenable all timers that depend on unit state */
765 LIST_FOREACH(value, v, t->values)
3742095b 766 if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
3ecaa09b 767 v->disabled = false;
01f78473 768
3ecaa09b 769 switch (t->state) {
871d7de4 770
3ecaa09b
LP
771 case TIMER_WAITING:
772 case TIMER_ELAPSED:
871d7de4 773
3ecaa09b
LP
774 /* Recalculate sleep time */
775 timer_enter_waiting(t, false);
776 break;
871d7de4 777
3ecaa09b 778 case TIMER_RUNNING:
871d7de4 779
3ecaa09b 780 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
f2341e0a 781 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
871d7de4 782 timer_enter_waiting(t, false);
3ecaa09b
LP
783 }
784 break;
871d7de4 785
3ecaa09b
LP
786 case TIMER_DEAD:
787 case TIMER_FAILED:
788 break;
871d7de4 789
3ecaa09b
LP
790 default:
791 assert_not_reached("Unknown timer state");
871d7de4 792 }
871d7de4
LP
793}
794
fdf20a31 795static void timer_reset_failed(Unit *u) {
5632e374
LP
796 Timer *t = TIMER(u);
797
798 assert(t);
799
fdf20a31 800 if (t->state == TIMER_FAILED)
5632e374
LP
801 timer_set_state(t, TIMER_DEAD);
802
067d72c9 803 t->result = TIMER_SUCCESS;
5632e374
LP
804}
805
8742514c
LP
806static void timer_time_change(Unit *u) {
807 Timer *t = TIMER(u);
808
809 assert(u);
810
811 if (t->state != TIMER_WAITING)
812 return;
813
f2341e0a 814 log_unit_debug(u, "Time change, recalculating next elapse.");
8742514c
LP
815 timer_enter_waiting(t, false);
816}
817
871d7de4 818static const char* const timer_base_table[_TIMER_BASE_MAX] = {
03fae018
LP
819 [TIMER_ACTIVE] = "OnActiveSec",
820 [TIMER_BOOT] = "OnBootSec",
821 [TIMER_STARTUP] = "OnStartupSec",
822 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
36697dc0
LP
823 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
824 [TIMER_CALENDAR] = "OnCalendar"
871d7de4
LP
825};
826
827DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
828
067d72c9
LP
829static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
830 [TIMER_SUCCESS] = "success",
07299350
LP
831 [TIMER_FAILURE_RESOURCES] = "resources",
832 [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
067d72c9
LP
833};
834
835DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
836
87f0e418 837const UnitVTable timer_vtable = {
7d17cfbc 838 .object_size = sizeof(Timer),
718db961 839
f975e971
LP
840 .sections =
841 "Unit\0"
842 "Timer\0"
843 "Install\0",
d8a812d1 844 .private_section = "Timer",
5cb5a6ff 845
871d7de4 846 .init = timer_init,
034c6ed7 847 .done = timer_done,
871d7de4
LP
848 .load = timer_load,
849
850 .coldplug = timer_coldplug,
851
852 .dump = timer_dump,
853
854 .start = timer_start,
855 .stop = timer_stop,
856
857 .serialize = timer_serialize,
858 .deserialize_item = timer_deserialize_item,
859
860 .active_state = timer_active_state,
861 .sub_state_to_string = timer_sub_state_to_string,
862
3ecaa09b
LP
863 .trigger_notify = timer_trigger_notify,
864
fdf20a31 865 .reset_failed = timer_reset_failed,
8742514c 866 .time_change = timer_time_change,
5632e374 867
718db961 868 .bus_vtable = bus_timer_vtable,
d8a812d1
WC
869 .bus_set_property = bus_timer_set_property,
870
871 .can_transient = true,
5cb5a6ff 872};