]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/timer.c
timedated: refuse manual system time updates when automatic timesync is enabled
[thirdparty/systemd.git] / src / core / timer.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5cb5a6ff 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
d46de8a1
LP
22#include <errno.h>
23
87f0e418 24#include "unit.h"
871d7de4 25#include "unit-name.h"
5cb5a6ff 26#include "timer.h"
871d7de4 27#include "dbus-timer.h"
a40eb732 28#include "special.h"
718db961
LP
29#include "bus-util.h"
30#include "bus-error.h"
06642d17 31#include "mkdir.h"
871d7de4
LP
32
33static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
34 [TIMER_DEAD] = UNIT_INACTIVE,
35 [TIMER_WAITING] = UNIT_ACTIVE,
36 [TIMER_RUNNING] = UNIT_ACTIVE,
37 [TIMER_ELAPSED] = UNIT_ACTIVE,
fdf20a31 38 [TIMER_FAILED] = UNIT_FAILED
871d7de4
LP
39};
40
718db961
LP
41static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
42
871d7de4
LP
43static void timer_init(Unit *u) {
44 Timer *t = TIMER(u);
45
46 assert(u);
ac155bb8 47 assert(u->load_state == UNIT_STUB);
871d7de4 48
dedabea4 49 t->next_elapse_monotonic_or_boottime = (usec_t) -1;
36697dc0 50 t->next_elapse_realtime = (usec_t) -1;
bd8f585b 51 t->accuracy_usec = u->manager->default_timer_accuracy_usec;
871d7de4 52}
5cb5a6ff 53
74051b9b 54void timer_free_values(Timer *t) {
871d7de4
LP
55 TimerValue *v;
56
57 assert(t);
58
59 while ((v = t->values)) {
71fda00f 60 LIST_REMOVE(value, t->values, v);
36697dc0
LP
61
62 if (v->calendar_spec)
63 calendar_spec_free(v->calendar_spec);
64
871d7de4
LP
65 free(v);
66 }
74051b9b
LP
67}
68
69static void timer_done(Unit *u) {
70 Timer *t = TIMER(u);
71
72 assert(t);
73
74 timer_free_values(t);
871d7de4 75
718db961
LP
76 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
77 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
06642d17
LP
78
79 free(t->stamp_path);
871d7de4
LP
80}
81
82static int timer_verify(Timer *t) {
83 assert(t);
84
1124fe6f 85 if (UNIT(t)->load_state != UNIT_LOADED)
871d7de4
LP
86 return 0;
87
88 if (!t->values) {
06642d17 89 log_error_unit(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
871d7de4
LP
90 return -EINVAL;
91 }
92
93 return 0;
94}
95
6c155fe3
LP
96static int timer_add_default_dependencies(Timer *t) {
97 int r;
98
99 assert(t);
100
e3d84721
LP
101 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
102 if (r < 0)
103 return r;
2a77d31d 104
e3d84721 105 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
36697dc0
LP
106 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
107 if (r < 0)
6c155fe3 108 return r;
2a77d31d 109 }
6c155fe3 110
ead8e478 111 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
6c155fe3
LP
112}
113
472fc28f
TB
114static void update_stampfile(Timer *t, usec_t timestamp) {
115 _cleanup_close_ int fd = -1;
116
117 mkdir_parents_label(t->stamp_path, 0755);
118
119 /* Update the file atime + mtime, if we can */
120 fd = open(t->stamp_path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
121 if (fd >= 0) {
122 struct timespec ts[2];
123
124 timespec_store(&ts[0], timestamp);
125 ts[1] = ts[0];
126
127 futimens(fd, ts);
128 }
129}
130
06642d17
LP
131static int timer_setup_persistent(Timer *t) {
132 int r;
133
134 assert(t);
135
136 if (!t->persistent)
137 return 0;
138
139 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
140
141 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
142 if (r < 0)
143 return r;
144
145 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
146 } else {
147 const char *e;
148
149 e = getenv("XDG_DATA_HOME");
150 if (e)
151 t->stamp_path = strjoin(e, "/systemd/timers/", UNIT(t)->id, NULL);
152 else {
153
154 _cleanup_free_ char *h = NULL;
155
156 r = get_home_dir(&h);
157 if (r < 0) {
158 log_error("Failed to determine home directory: %s", strerror(-r));
159 return r;
160 }
161
162 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
163 }
164 }
165
166 if (!t->stamp_path)
167 return log_oom();
168
169 return 0;
170}
171
871d7de4
LP
172static int timer_load(Unit *u) {
173 Timer *t = TIMER(u);
174 int r;
175
176 assert(u);
ac155bb8 177 assert(u->load_state == UNIT_STUB);
871d7de4 178
36697dc0
LP
179 r = unit_load_fragment_and_dropin(u);
180 if (r < 0)
871d7de4
LP
181 return r;
182
ac155bb8 183 if (u->load_state == UNIT_LOADED) {
871d7de4 184
3ecaa09b 185 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
57020a3a
LP
186 Unit *x;
187
188 r = unit_load_related_unit(u, ".service", &x);
189 if (r < 0)
871d7de4
LP
190 return r;
191
3ecaa09b
LP
192 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
193 if (r < 0)
194 return r;
57020a3a
LP
195 }
196
06642d17
LP
197 r = timer_setup_persistent(t);
198 if (r < 0)
199 return r;
200
201 if (u->default_dependencies) {
36697dc0
LP
202 r = timer_add_default_dependencies(t);
203 if (r < 0)
a40eb732 204 return r;
36697dc0 205 }
871d7de4
LP
206 }
207
208 return timer_verify(t);
209}
210
211static void timer_dump(Unit *u, FILE *f, const char *prefix) {
9f5eb56a 212 char buf[FORMAT_TIMESPAN_MAX];
871d7de4 213 Timer *t = TIMER(u);
3ecaa09b 214 Unit *trigger;
871d7de4 215 TimerValue *v;
034c6ed7 216
3ecaa09b
LP
217 trigger = UNIT_TRIGGER(u);
218
871d7de4
LP
219 fprintf(f,
220 "%sTimer State: %s\n"
067d72c9 221 "%sResult: %s\n"
9f5eb56a 222 "%sUnit: %s\n"
dedabea4
LP
223 "%sPersistent: %s\n"
224 "%sWakeSystem: %s\n"
9f5eb56a 225 "%sAccuracy: %s\n",
871d7de4 226 prefix, timer_state_to_string(t->state),
067d72c9 227 prefix, timer_result_to_string(t->result),
9f5eb56a 228 prefix, trigger ? trigger->id : "n/a",
dedabea4
LP
229 prefix, yes_no(t->persistent),
230 prefix, yes_no(t->wake_system),
9f5eb56a 231 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
871d7de4 232
36697dc0
LP
233 LIST_FOREACH(value, v, t->values) {
234
235 if (v->base == TIMER_CALENDAR) {
236 _cleanup_free_ char *p = NULL;
237
238 calendar_spec_to_string(v->calendar_spec, &p);
239
240 fprintf(f,
241 "%s%s: %s\n",
242 prefix,
243 timer_base_to_string(v->base),
244 strna(p));
245 } else {
246 char timespan1[FORMAT_TIMESPAN_MAX];
247
248 fprintf(f,
249 "%s%s: %s\n",
250 prefix,
251 timer_base_to_string(v->base),
2fa4092c 252 strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0)));
36697dc0
LP
253 }
254 }
871d7de4
LP
255}
256
257static void timer_set_state(Timer *t, TimerState state) {
258 TimerState old_state;
034c6ed7 259 assert(t);
871d7de4
LP
260
261 old_state = t->state;
262 t->state = state;
263
36697dc0 264 if (state != TIMER_WAITING) {
718db961
LP
265 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
266 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
36697dc0 267 }
871d7de4
LP
268
269 if (state != old_state)
66870f90
ZJS
270 log_debug_unit(UNIT(t)->id,
271 "%s changed %s -> %s", UNIT(t)->id,
272 timer_state_to_string(old_state),
273 timer_state_to_string(state));
871d7de4 274
e2f3b44c 275 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
871d7de4
LP
276}
277
278static void timer_enter_waiting(Timer *t, bool initial);
279
280static int timer_coldplug(Unit *u) {
281 Timer *t = TIMER(u);
282
283 assert(t);
284 assert(t->state == TIMER_DEAD);
285
286 if (t->deserialized_state != t->state) {
287
b363ca6f 288 if (t->deserialized_state == TIMER_WAITING)
871d7de4
LP
289 timer_enter_waiting(t, false);
290 else
291 timer_set_state(t, t->deserialized_state);
292 }
293
294 return 0;
295}
296
067d72c9 297static void timer_enter_dead(Timer *t, TimerResult f) {
871d7de4
LP
298 assert(t);
299
067d72c9
LP
300 if (f != TIMER_SUCCESS)
301 t->result = f;
871d7de4 302
067d72c9 303 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
871d7de4
LP
304}
305
dedabea4
LP
306static usec_t monotonic_to_boottime(usec_t t) {
307 usec_t a, b;
308
309 if (t <= 0)
310 return 0;
311
312 a = now(CLOCK_BOOTTIME);
313 b = now(CLOCK_MONOTONIC);
314
315 if (t + a > b)
316 return t + a - b;
317 else
318 return 0;
319}
320
871d7de4 321static void timer_enter_waiting(Timer *t, bool initial) {
36697dc0 322 bool found_monotonic = false, found_realtime = false;
dedabea4
LP
323 usec_t ts_realtime, ts_monotonic;
324 usec_t base = 0;
325 TimerValue *v;
871d7de4
LP
326 int r;
327
dedabea4
LP
328 /* If we shall wake the system we use the boottime clock
329 * rather than the monotonic clock. */
330
331 ts_realtime = now(CLOCK_REALTIME);
332 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
333 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
871d7de4
LP
334
335 LIST_FOREACH(value, v, t->values) {
336
337 if (v->disabled)
338 continue;
339
36697dc0 340 if (v->base == TIMER_CALENDAR) {
06642d17
LP
341 usec_t b;
342
343 /* If we know the last time this was
344 * triggered, schedule the job based relative
345 * to that. If we don't just start from
346 * now. */
36697dc0 347
dedabea4 348 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
06642d17
LP
349
350 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
36697dc0
LP
351 if (r < 0)
352 continue;
353
36697dc0
LP
354 if (!found_realtime)
355 t->next_elapse_realtime = v->next_elapse;
10717a1a 356 else
36697dc0 357 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
871d7de4 358
36697dc0 359 found_realtime = true;
871d7de4 360
36697dc0
LP
361 } else {
362 switch (v->base) {
871d7de4 363
36697dc0
LP
364 case TIMER_ACTIVE:
365 if (state_translation_table[t->state] == UNIT_ACTIVE)
366 base = UNIT(t)->inactive_exit_timestamp.monotonic;
367 else
dedabea4 368 base = ts_monotonic;
36697dc0 369 break;
871d7de4 370
36697dc0
LP
371 case TIMER_BOOT:
372 /* CLOCK_MONOTONIC equals the uptime on Linux */
373 base = 0;
374 break;
871d7de4 375
36697dc0
LP
376 case TIMER_STARTUP:
377 base = UNIT(t)->manager->userspace_timestamp.monotonic;
378 break;
871d7de4 379
36697dc0 380 case TIMER_UNIT_ACTIVE:
871d7de4 381
e41e1943
LP
382 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
383
384 if (base <= 0)
06642d17 385 base = t->last_trigger.monotonic;
e41e1943
LP
386
387 if (base <= 0)
36697dc0 388 continue;
871d7de4 389
36697dc0 390 break;
871d7de4 391
36697dc0 392 case TIMER_UNIT_INACTIVE:
871d7de4 393
e41e1943
LP
394 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
395
396 if (base <= 0)
06642d17 397 base = t->last_trigger.monotonic;
e41e1943
LP
398
399 if (base <= 0)
36697dc0 400 continue;
871d7de4 401
36697dc0 402 break;
871d7de4 403
36697dc0
LP
404 default:
405 assert_not_reached("Unknown timer base");
406 }
871d7de4 407
dedabea4
LP
408 if (t->wake_system)
409 base = monotonic_to_boottime(base);
410
36697dc0
LP
411 v->next_elapse = base + v->value;
412
dedabea4 413 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
e41e1943 414 /* This is a one time trigger, disable it now */
36697dc0
LP
415 v->disabled = true;
416 continue;
417 }
418
419 if (!found_monotonic)
dedabea4 420 t->next_elapse_monotonic_or_boottime = v->next_elapse;
36697dc0 421 else
dedabea4 422 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
36697dc0
LP
423
424 found_monotonic = true;
425 }
871d7de4
LP
426 }
427
36697dc0 428 if (!found_monotonic && !found_realtime) {
66870f90 429 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
871d7de4
LP
430 timer_set_state(t, TIMER_ELAPSED);
431 return;
432 }
433
36697dc0
LP
434 if (found_monotonic) {
435 char buf[FORMAT_TIMESPAN_MAX];
dedabea4
LP
436
437 log_debug_unit(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
438 UNIT(t)->id,
439 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
871d7de4 440
718db961 441 if (t->monotonic_event_source) {
dedabea4 442 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
718db961
LP
443 if (r < 0)
444 goto fail;
445
446 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
447 } else
6a0f1f6d
LP
448 r = sd_event_add_time(
449 UNIT(t)->manager->event,
450 &t->monotonic_event_source,
dedabea4
LP
451 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
452 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
6a0f1f6d 453 timer_dispatch, t);
36697dc0
LP
454 if (r < 0)
455 goto fail;
718db961
LP
456
457 } else if (t->monotonic_event_source) {
718db961 458
06642d17 459 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
718db961
LP
460 if (r < 0)
461 goto fail;
462 }
36697dc0
LP
463
464 if (found_realtime) {
465 char buf[FORMAT_TIMESTAMP_MAX];
06642d17 466 log_debug_unit(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
36697dc0 467
718db961
LP
468 if (t->realtime_event_source) {
469 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
470 if (r < 0)
471 goto fail;
472
473 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
474 } else
6a0f1f6d
LP
475 r = sd_event_add_time(
476 UNIT(t)->manager->event,
477 &t->realtime_event_source,
dedabea4 478 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
6a0f1f6d
LP
479 t->next_elapse_realtime, t->accuracy_usec,
480 timer_dispatch, t);
36697dc0
LP
481 if (r < 0)
482 goto fail;
718db961
LP
483
484 } else if (t->realtime_event_source) {
718db961 485
06642d17 486 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
718db961
LP
487 if (r < 0)
488 goto fail;
489 }
871d7de4
LP
490
491 timer_set_state(t, TIMER_WAITING);
492 return;
493
494fail:
06642d17 495 log_warning_unit(UNIT(t)->id, "%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
067d72c9 496 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
497}
498
499static void timer_enter_running(Timer *t) {
718db961 500 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
871d7de4 501 int r;
398ef8ba 502
871d7de4
LP
503 assert(t);
504
ba3e67a7 505 /* Don't start job if we are supposed to go down */
31afa0a4 506 if (unit_stop_pending(UNIT(t)))
ba3e67a7
LP
507 return;
508
3ecaa09b
LP
509 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
510 JOB_REPLACE, true, &error, NULL);
36697dc0 511 if (r < 0)
871d7de4
LP
512 goto fail;
513
06642d17
LP
514 dual_timestamp_get(&t->last_trigger);
515
472fc28f
TB
516 if (t->stamp_path)
517 update_stampfile(t, t->last_trigger.realtime);
e41e1943 518
871d7de4
LP
519 timer_set_state(t, TIMER_RUNNING);
520 return;
521
522fail:
66870f90
ZJS
523 log_warning_unit(UNIT(t)->id,
524 "%s failed to queue unit startup job: %s",
718db961 525 UNIT(t)->id, bus_error_message(&error, r));
067d72c9 526 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
527}
528
529static int timer_start(Unit *u) {
530 Timer *t = TIMER(u);
531
532 assert(t);
fdf20a31 533 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
01f78473 534
3ecaa09b 535 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
01f78473 536 return -ENOENT;
871d7de4 537
06642d17
LP
538 t->last_trigger = DUAL_TIMESTAMP_NULL;
539
540 if (t->stamp_path) {
541 struct stat st;
542
543 if (stat(t->stamp_path, &st) >= 0)
544 t->last_trigger.realtime = timespec_load(&st.st_atim);
472fc28f
TB
545 else if (errno == ENOENT)
546 /* The timer has never run before,
547 * make sure a stamp file exists.
548 */
549 update_stampfile(t, now(CLOCK_REALTIME));
06642d17
LP
550 }
551
067d72c9 552 t->result = TIMER_SUCCESS;
871d7de4
LP
553 timer_enter_waiting(t, true);
554 return 0;
555}
556
557static int timer_stop(Unit *u) {
558 Timer *t = TIMER(u);
559
560 assert(t);
561 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
562
067d72c9 563 timer_enter_dead(t, TIMER_SUCCESS);
871d7de4
LP
564 return 0;
565}
566
567static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
568 Timer *t = TIMER(u);
569
570 assert(u);
571 assert(f);
572 assert(fds);
573
574 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
067d72c9 575 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
871d7de4 576
06642d17
LP
577 if (t->last_trigger.realtime > 0)
578 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
579
580 if (t->last_trigger.monotonic > 0)
581 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
582
871d7de4
LP
583 return 0;
584}
585
586static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
587 Timer *t = TIMER(u);
06642d17 588 int r;
871d7de4
LP
589
590 assert(u);
591 assert(key);
592 assert(value);
593 assert(fds);
594
595 if (streq(key, "state")) {
596 TimerState state;
597
36697dc0
LP
598 state = timer_state_from_string(value);
599 if (state < 0)
66870f90 600 log_debug_unit(u->id, "Failed to parse state value %s", value);
871d7de4
LP
601 else
602 t->deserialized_state = state;
067d72c9
LP
603 } else if (streq(key, "result")) {
604 TimerResult f;
605
606 f = timer_result_from_string(value);
607 if (f < 0)
66870f90 608 log_debug_unit(u->id, "Failed to parse result value %s", value);
067d72c9
LP
609 else if (f != TIMER_SUCCESS)
610 t->result = f;
06642d17
LP
611 } else if (streq(key, "last-trigger-realtime")) {
612
613 r = safe_atou64(value, &t->last_trigger.realtime);
614 if (r < 0)
615 log_debug_unit(u->id, "Failed to parse last-trigger-realtime value %s", value);
616
617 } else if (streq(key, "last-trigger-monotonic")) {
618
619 r = safe_atou64(value, &t->last_trigger.monotonic);
620 if (r < 0)
621 log_debug_unit(u->id, "Failed to parse last-trigger-monotonic value %s", value);
067d72c9 622
871d7de4 623 } else
66870f90 624 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
871d7de4
LP
625
626 return 0;
034c6ed7
LP
627}
628
44a6b1b6 629_pure_ static UnitActiveState timer_active_state(Unit *u) {
871d7de4
LP
630 assert(u);
631
632 return state_translation_table[TIMER(u)->state];
633}
634
44a6b1b6 635_pure_ static const char *timer_sub_state_to_string(Unit *u) {
871d7de4
LP
636 assert(u);
637
638 return timer_state_to_string(TIMER(u)->state);
639}
640
718db961
LP
641static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
642 Timer *t = TIMER(userdata);
871d7de4
LP
643
644 assert(t);
5cb5a6ff 645
871d7de4 646 if (t->state != TIMER_WAITING)
718db961 647 return 0;
5cb5a6ff 648
718db961 649 log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
871d7de4 650 timer_enter_running(t);
718db961 651 return 0;
5cb5a6ff
LP
652}
653
3ecaa09b
LP
654static void timer_trigger_notify(Unit *u, Unit *other) {
655 Timer *t = TIMER(u);
656 TimerValue *v;
871d7de4 657
3ecaa09b
LP
658 assert(u);
659 assert(other);
871d7de4 660
3ecaa09b
LP
661 if (other->load_state != UNIT_LOADED)
662 return;
871d7de4 663
3ecaa09b
LP
664 /* Reenable all timers that depend on unit state */
665 LIST_FOREACH(value, v, t->values)
666 if (v->base == TIMER_UNIT_ACTIVE ||
667 v->base == TIMER_UNIT_INACTIVE)
668 v->disabled = false;
01f78473 669
3ecaa09b 670 switch (t->state) {
871d7de4 671
3ecaa09b
LP
672 case TIMER_WAITING:
673 case TIMER_ELAPSED:
871d7de4 674
3ecaa09b
LP
675 /* Recalculate sleep time */
676 timer_enter_waiting(t, false);
677 break;
871d7de4 678
3ecaa09b 679 case TIMER_RUNNING:
871d7de4 680
3ecaa09b 681 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
06642d17 682 log_debug_unit(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
871d7de4 683 timer_enter_waiting(t, false);
3ecaa09b
LP
684 }
685 break;
871d7de4 686
3ecaa09b
LP
687 case TIMER_DEAD:
688 case TIMER_FAILED:
689 break;
871d7de4 690
3ecaa09b
LP
691 default:
692 assert_not_reached("Unknown timer state");
871d7de4 693 }
871d7de4
LP
694}
695
fdf20a31 696static void timer_reset_failed(Unit *u) {
5632e374
LP
697 Timer *t = TIMER(u);
698
699 assert(t);
700
fdf20a31 701 if (t->state == TIMER_FAILED)
5632e374
LP
702 timer_set_state(t, TIMER_DEAD);
703
067d72c9 704 t->result = TIMER_SUCCESS;
5632e374
LP
705}
706
8742514c
LP
707static void timer_time_change(Unit *u) {
708 Timer *t = TIMER(u);
709
710 assert(u);
711
712 if (t->state != TIMER_WAITING)
713 return;
714
06642d17 715 log_debug_unit(u->id, "%s: time change, recalculating next elapse.", u->id);
8742514c
LP
716 timer_enter_waiting(t, false);
717}
718
871d7de4
LP
719static const char* const timer_state_table[_TIMER_STATE_MAX] = {
720 [TIMER_DEAD] = "dead",
721 [TIMER_WAITING] = "waiting",
722 [TIMER_RUNNING] = "running",
723 [TIMER_ELAPSED] = "elapsed",
fdf20a31 724 [TIMER_FAILED] = "failed"
871d7de4
LP
725};
726
727DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
728
729static const char* const timer_base_table[_TIMER_BASE_MAX] = {
03fae018
LP
730 [TIMER_ACTIVE] = "OnActiveSec",
731 [TIMER_BOOT] = "OnBootSec",
732 [TIMER_STARTUP] = "OnStartupSec",
733 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
36697dc0
LP
734 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
735 [TIMER_CALENDAR] = "OnCalendar"
871d7de4
LP
736};
737
738DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
739
067d72c9
LP
740static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
741 [TIMER_SUCCESS] = "success",
742 [TIMER_FAILURE_RESOURCES] = "resources"
743};
744
745DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
746
87f0e418 747const UnitVTable timer_vtable = {
7d17cfbc 748 .object_size = sizeof(Timer),
718db961 749
f975e971
LP
750 .sections =
751 "Unit\0"
752 "Timer\0"
753 "Install\0",
5cb5a6ff 754
871d7de4 755 .init = timer_init,
034c6ed7 756 .done = timer_done,
871d7de4
LP
757 .load = timer_load,
758
759 .coldplug = timer_coldplug,
760
761 .dump = timer_dump,
762
763 .start = timer_start,
764 .stop = timer_stop,
765
766 .serialize = timer_serialize,
767 .deserialize_item = timer_deserialize_item,
768
769 .active_state = timer_active_state,
770 .sub_state_to_string = timer_sub_state_to_string,
771
3ecaa09b
LP
772 .trigger_notify = timer_trigger_notify,
773
fdf20a31 774 .reset_failed = timer_reset_failed,
8742514c 775 .time_change = timer_time_change,
5632e374 776
c4e2ceae 777 .bus_interface = "org.freedesktop.systemd1.Timer",
718db961 778 .bus_vtable = bus_timer_vtable,
5cb5a6ff 779};