]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/timer.c
core: remove support for RequiresOverridable= and RequisiteOverridable=
[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
b5efdb8a 24#include "alloc-util.h"
07630cea
LP
25#include "bus-error.h"
26#include "bus-util.h"
871d7de4 27#include "dbus-timer.h"
f4f15635 28#include "fs-util.h"
6bedfcbb 29#include "parse-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;
871d7de4 58}
5cb5a6ff 59
74051b9b 60void timer_free_values(Timer *t) {
871d7de4
LP
61 TimerValue *v;
62
63 assert(t);
64
65 while ((v = t->values)) {
71fda00f 66 LIST_REMOVE(value, t->values, v);
3e044c49 67 calendar_spec_free(v->calendar_spec);
871d7de4
LP
68 free(v);
69 }
74051b9b
LP
70}
71
72static void timer_done(Unit *u) {
73 Timer *t = TIMER(u);
74
75 assert(t);
76
77 timer_free_values(t);
871d7de4 78
718db961
LP
79 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
80 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
06642d17
LP
81
82 free(t->stamp_path);
871d7de4
LP
83}
84
85static int timer_verify(Timer *t) {
86 assert(t);
87
1124fe6f 88 if (UNIT(t)->load_state != UNIT_LOADED)
871d7de4
LP
89 return 0;
90
91 if (!t->values) {
f2341e0a 92 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
871d7de4
LP
93 return -EINVAL;
94 }
95
96 return 0;
97}
98
6c155fe3
LP
99static int timer_add_default_dependencies(Timer *t) {
100 int r;
19f8d037 101 TimerValue *v;
6c155fe3
LP
102
103 assert(t);
104
4c9ea260
LP
105 if (!UNIT(t)->default_dependencies)
106 return 0;
107
e3d84721
LP
108 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
109 if (r < 0)
110 return r;
2a77d31d 111
b2c23da8 112 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
36697dc0
LP
113 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
114 if (r < 0)
6c155fe3 115 return r;
19f8d037
TGR
116
117 LIST_FOREACH(value, v, t->values) {
118 if (v->base == TIMER_CALENDAR) {
119 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
120 if (r < 0)
121 return r;
122 break;
123 }
124 }
2a77d31d 125 }
6c155fe3 126
ead8e478 127 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
6c155fe3
LP
128}
129
06642d17
LP
130static int timer_setup_persistent(Timer *t) {
131 int r;
132
133 assert(t);
134
135 if (!t->persistent)
136 return 0;
137
b2c23da8 138 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
06642d17
LP
139
140 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
141 if (r < 0)
142 return r;
143
144 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
145 } else {
146 const char *e;
147
148 e = getenv("XDG_DATA_HOME");
149 if (e)
bd34b310 150 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
06642d17
LP
151 else {
152
153 _cleanup_free_ char *h = NULL;
154
155 r = get_home_dir(&h);
23bbb0de 156 if (r < 0)
f2341e0a 157 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
06642d17
LP
158
159 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
160 }
161 }
162
163 if (!t->stamp_path)
164 return log_oom();
165
166 return 0;
167}
168
871d7de4
LP
169static int timer_load(Unit *u) {
170 Timer *t = TIMER(u);
171 int r;
172
173 assert(u);
ac155bb8 174 assert(u->load_state == UNIT_STUB);
871d7de4 175
36697dc0
LP
176 r = unit_load_fragment_and_dropin(u);
177 if (r < 0)
871d7de4
LP
178 return r;
179
ac155bb8 180 if (u->load_state == UNIT_LOADED) {
871d7de4 181
3ecaa09b 182 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
57020a3a
LP
183 Unit *x;
184
185 r = unit_load_related_unit(u, ".service", &x);
186 if (r < 0)
871d7de4
LP
187 return r;
188
3ecaa09b
LP
189 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
190 if (r < 0)
191 return r;
57020a3a
LP
192 }
193
06642d17
LP
194 r = timer_setup_persistent(t);
195 if (r < 0)
196 return r;
197
4c9ea260
LP
198 r = timer_add_default_dependencies(t);
199 if (r < 0)
200 return r;
871d7de4
LP
201 }
202
203 return timer_verify(t);
204}
205
206static void timer_dump(Unit *u, FILE *f, const char *prefix) {
9f5eb56a 207 char buf[FORMAT_TIMESPAN_MAX];
871d7de4 208 Timer *t = TIMER(u);
3ecaa09b 209 Unit *trigger;
871d7de4 210 TimerValue *v;
034c6ed7 211
3ecaa09b
LP
212 trigger = UNIT_TRIGGER(u);
213
871d7de4
LP
214 fprintf(f,
215 "%sTimer State: %s\n"
067d72c9 216 "%sResult: %s\n"
9f5eb56a 217 "%sUnit: %s\n"
dedabea4
LP
218 "%sPersistent: %s\n"
219 "%sWakeSystem: %s\n"
9f5eb56a 220 "%sAccuracy: %s\n",
871d7de4 221 prefix, timer_state_to_string(t->state),
067d72c9 222 prefix, timer_result_to_string(t->result),
9f5eb56a 223 prefix, trigger ? trigger->id : "n/a",
dedabea4
LP
224 prefix, yes_no(t->persistent),
225 prefix, yes_no(t->wake_system),
9f5eb56a 226 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
871d7de4 227
36697dc0
LP
228 LIST_FOREACH(value, v, t->values) {
229
230 if (v->base == TIMER_CALENDAR) {
231 _cleanup_free_ char *p = NULL;
232
233 calendar_spec_to_string(v->calendar_spec, &p);
234
235 fprintf(f,
236 "%s%s: %s\n",
237 prefix,
238 timer_base_to_string(v->base),
239 strna(p));
240 } else {
241 char timespan1[FORMAT_TIMESPAN_MAX];
242
243 fprintf(f,
244 "%s%s: %s\n",
245 prefix,
246 timer_base_to_string(v->base),
b1d6dcf5 247 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
36697dc0
LP
248 }
249 }
871d7de4
LP
250}
251
252static void timer_set_state(Timer *t, TimerState state) {
253 TimerState old_state;
034c6ed7 254 assert(t);
871d7de4
LP
255
256 old_state = t->state;
257 t->state = state;
258
36697dc0 259 if (state != TIMER_WAITING) {
718db961
LP
260 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
261 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
36697dc0 262 }
871d7de4
LP
263
264 if (state != old_state)
f2341e0a 265 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
871d7de4 266
e2f3b44c 267 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
871d7de4
LP
268}
269
270static void timer_enter_waiting(Timer *t, bool initial);
271
be847e82 272static int timer_coldplug(Unit *u) {
871d7de4
LP
273 Timer *t = TIMER(u);
274
275 assert(t);
276 assert(t->state == TIMER_DEAD);
277
278 if (t->deserialized_state != t->state) {
279
be847e82
LP
280 if (t->deserialized_state == TIMER_WAITING)
281 timer_enter_waiting(t, false);
282 else
871d7de4
LP
283 timer_set_state(t, t->deserialized_state);
284 }
285
286 return 0;
287}
288
067d72c9 289static void timer_enter_dead(Timer *t, TimerResult f) {
871d7de4
LP
290 assert(t);
291
067d72c9
LP
292 if (f != TIMER_SUCCESS)
293 t->result = f;
871d7de4 294
067d72c9 295 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
871d7de4
LP
296}
297
dedabea4
LP
298static usec_t monotonic_to_boottime(usec_t t) {
299 usec_t a, b;
300
301 if (t <= 0)
302 return 0;
303
304 a = now(CLOCK_BOOTTIME);
305 b = now(CLOCK_MONOTONIC);
306
307 if (t + a > b)
308 return t + a - b;
309 else
310 return 0;
311}
312
871d7de4 313static void timer_enter_waiting(Timer *t, bool initial) {
36697dc0 314 bool found_monotonic = false, found_realtime = false;
dedabea4
LP
315 usec_t ts_realtime, ts_monotonic;
316 usec_t base = 0;
317 TimerValue *v;
871d7de4
LP
318 int r;
319
dedabea4
LP
320 /* If we shall wake the system we use the boottime clock
321 * rather than the monotonic clock. */
322
323 ts_realtime = now(CLOCK_REALTIME);
324 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
325 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
871d7de4
LP
326
327 LIST_FOREACH(value, v, t->values) {
328
329 if (v->disabled)
330 continue;
331
36697dc0 332 if (v->base == TIMER_CALENDAR) {
06642d17
LP
333 usec_t b;
334
335 /* If we know the last time this was
336 * triggered, schedule the job based relative
337 * to that. If we don't just start from
338 * now. */
36697dc0 339
dedabea4 340 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
06642d17
LP
341
342 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
36697dc0
LP
343 if (r < 0)
344 continue;
345
36697dc0
LP
346 if (!found_realtime)
347 t->next_elapse_realtime = v->next_elapse;
10717a1a 348 else
36697dc0 349 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
871d7de4 350
36697dc0 351 found_realtime = true;
871d7de4 352
36697dc0
LP
353 } else {
354 switch (v->base) {
871d7de4 355
36697dc0
LP
356 case TIMER_ACTIVE:
357 if (state_translation_table[t->state] == UNIT_ACTIVE)
358 base = UNIT(t)->inactive_exit_timestamp.monotonic;
359 else
dedabea4 360 base = ts_monotonic;
36697dc0 361 break;
871d7de4 362
36697dc0 363 case TIMER_BOOT:
c1d9ba99
MS
364 if (detect_container() <= 0) {
365 /* CLOCK_MONOTONIC equals the uptime on Linux */
366 base = 0;
367 break;
368 }
369 /* In a container we don't want to include the time the host
370 * was already up when the container started, so count from
371 * our own startup. Fall through. */
36697dc0
LP
372 case TIMER_STARTUP:
373 base = UNIT(t)->manager->userspace_timestamp.monotonic;
374 break;
871d7de4 375
36697dc0 376 case TIMER_UNIT_ACTIVE:
871d7de4 377
e41e1943
LP
378 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
379
380 if (base <= 0)
06642d17 381 base = t->last_trigger.monotonic;
e41e1943
LP
382
383 if (base <= 0)
36697dc0 384 continue;
871d7de4 385
36697dc0 386 break;
871d7de4 387
36697dc0 388 case TIMER_UNIT_INACTIVE:
871d7de4 389
e41e1943
LP
390 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
391
392 if (base <= 0)
06642d17 393 base = t->last_trigger.monotonic;
e41e1943
LP
394
395 if (base <= 0)
36697dc0 396 continue;
871d7de4 397
36697dc0 398 break;
871d7de4 399
36697dc0
LP
400 default:
401 assert_not_reached("Unknown timer base");
402 }
871d7de4 403
dedabea4
LP
404 if (t->wake_system)
405 base = monotonic_to_boottime(base);
406
36697dc0
LP
407 v->next_elapse = base + v->value;
408
dedabea4 409 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
e41e1943 410 /* This is a one time trigger, disable it now */
36697dc0
LP
411 v->disabled = true;
412 continue;
413 }
414
415 if (!found_monotonic)
dedabea4 416 t->next_elapse_monotonic_or_boottime = v->next_elapse;
36697dc0 417 else
dedabea4 418 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
36697dc0
LP
419
420 found_monotonic = true;
421 }
871d7de4
LP
422 }
423
36697dc0 424 if (!found_monotonic && !found_realtime) {
f2341e0a 425 log_unit_debug(UNIT(t), "Timer is elapsed.");
871d7de4
LP
426 timer_set_state(t, TIMER_ELAPSED);
427 return;
428 }
429
36697dc0
LP
430 if (found_monotonic) {
431 char buf[FORMAT_TIMESPAN_MAX];
dedabea4 432
f2341e0a 433 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
871d7de4 434
718db961 435 if (t->monotonic_event_source) {
dedabea4 436 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
718db961
LP
437 if (r < 0)
438 goto fail;
439
440 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
cbf60d0a
LP
441 if (r < 0)
442 goto fail;
443 } else {
444
6a0f1f6d
LP
445 r = sd_event_add_time(
446 UNIT(t)->manager->event,
447 &t->monotonic_event_source,
dedabea4
LP
448 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
449 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
6a0f1f6d 450 timer_dispatch, t);
cbf60d0a
LP
451 if (r < 0)
452 goto fail;
718db961 453
cbf60d0a
LP
454 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
455 }
7dfbe2e3 456
718db961 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];
f2341e0a 466 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", 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);
cbf60d0a
LP
474 if (r < 0)
475 goto fail;
476 } else {
6a0f1f6d
LP
477 r = sd_event_add_time(
478 UNIT(t)->manager->event,
479 &t->realtime_event_source,
dedabea4 480 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
6a0f1f6d
LP
481 t->next_elapse_realtime, t->accuracy_usec,
482 timer_dispatch, t);
cbf60d0a
LP
483 if (r < 0)
484 goto fail;
718db961 485
cbf60d0a
LP
486 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
487 }
7dfbe2e3 488
718db961 489 } else if (t->realtime_event_source) {
718db961 490
06642d17 491 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
718db961
LP
492 if (r < 0)
493 goto fail;
494 }
871d7de4
LP
495
496 timer_set_state(t, TIMER_WAITING);
497 return;
498
499fail:
f2341e0a 500 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
067d72c9 501 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
502}
503
504static void timer_enter_running(Timer *t) {
718db961 505 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
871d7de4 506 int r;
398ef8ba 507
871d7de4
LP
508 assert(t);
509
ba3e67a7 510 /* Don't start job if we are supposed to go down */
31afa0a4 511 if (unit_stop_pending(UNIT(t)))
ba3e67a7
LP
512 return;
513
3ecaa09b
LP
514 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
515 JOB_REPLACE, true, &error, NULL);
36697dc0 516 if (r < 0)
871d7de4
LP
517 goto fail;
518
06642d17
LP
519 dual_timestamp_get(&t->last_trigger);
520
472fc28f 521 if (t->stamp_path)
ee735086 522 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
e41e1943 523
871d7de4
LP
524 timer_set_state(t, TIMER_RUNNING);
525 return;
526
527fail:
f2341e0a 528 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
067d72c9 529 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
530}
531
532static int timer_start(Unit *u) {
533 Timer *t = TIMER(u);
779042e7 534 TimerValue *v;
871d7de4
LP
535
536 assert(t);
fdf20a31 537 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
01f78473 538
3ecaa09b 539 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
01f78473 540 return -ENOENT;
871d7de4 541
06642d17
LP
542 t->last_trigger = DUAL_TIMESTAMP_NULL;
543
779042e7
MC
544 /* Reenable all timers that depend on unit activation time */
545 LIST_FOREACH(value, v, t->values)
546 if (v->base == TIMER_ACTIVE)
547 v->disabled = false;
548
06642d17
LP
549 if (t->stamp_path) {
550 struct stat st;
551
552 if (stat(t->stamp_path, &st) >= 0)
553 t->last_trigger.realtime = timespec_load(&st.st_atim);
472fc28f
TB
554 else if (errno == ENOENT)
555 /* The timer has never run before,
556 * make sure a stamp file exists.
557 */
ee735086 558 touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
06642d17
LP
559 }
560
067d72c9 561 t->result = TIMER_SUCCESS;
871d7de4 562 timer_enter_waiting(t, true);
82a2b6bb 563 return 1;
871d7de4
LP
564}
565
566static int timer_stop(Unit *u) {
567 Timer *t = TIMER(u);
568
569 assert(t);
570 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
571
067d72c9 572 timer_enter_dead(t, TIMER_SUCCESS);
82a2b6bb 573 return 1;
871d7de4
LP
574}
575
576static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
577 Timer *t = TIMER(u);
578
579 assert(u);
580 assert(f);
581 assert(fds);
582
583 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
067d72c9 584 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
871d7de4 585
06642d17
LP
586 if (t->last_trigger.realtime > 0)
587 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
588
589 if (t->last_trigger.monotonic > 0)
590 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
591
871d7de4
LP
592 return 0;
593}
594
595static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
596 Timer *t = TIMER(u);
06642d17 597 int r;
871d7de4
LP
598
599 assert(u);
600 assert(key);
601 assert(value);
602 assert(fds);
603
604 if (streq(key, "state")) {
605 TimerState state;
606
36697dc0
LP
607 state = timer_state_from_string(value);
608 if (state < 0)
f2341e0a 609 log_unit_debug(u, "Failed to parse state value: %s", value);
871d7de4
LP
610 else
611 t->deserialized_state = state;
067d72c9
LP
612 } else if (streq(key, "result")) {
613 TimerResult f;
614
615 f = timer_result_from_string(value);
616 if (f < 0)
f2341e0a 617 log_unit_debug(u, "Failed to parse result value: %s", value);
067d72c9
LP
618 else if (f != TIMER_SUCCESS)
619 t->result = f;
06642d17
LP
620 } else if (streq(key, "last-trigger-realtime")) {
621
622 r = safe_atou64(value, &t->last_trigger.realtime);
623 if (r < 0)
f2341e0a 624 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
06642d17
LP
625
626 } else if (streq(key, "last-trigger-monotonic")) {
627
628 r = safe_atou64(value, &t->last_trigger.monotonic);
629 if (r < 0)
f2341e0a 630 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
067d72c9 631
871d7de4 632 } else
f2341e0a 633 log_unit_debug(u, "Unknown serialization key: %s", key);
871d7de4
LP
634
635 return 0;
034c6ed7
LP
636}
637
44a6b1b6 638_pure_ static UnitActiveState timer_active_state(Unit *u) {
871d7de4
LP
639 assert(u);
640
641 return state_translation_table[TIMER(u)->state];
642}
643
44a6b1b6 644_pure_ static const char *timer_sub_state_to_string(Unit *u) {
871d7de4
LP
645 assert(u);
646
647 return timer_state_to_string(TIMER(u)->state);
648}
649
718db961
LP
650static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
651 Timer *t = TIMER(userdata);
871d7de4
LP
652
653 assert(t);
5cb5a6ff 654
871d7de4 655 if (t->state != TIMER_WAITING)
718db961 656 return 0;
5cb5a6ff 657
f2341e0a 658 log_unit_debug(UNIT(t), "Timer elapsed.");
871d7de4 659 timer_enter_running(t);
718db961 660 return 0;
5cb5a6ff
LP
661}
662
3ecaa09b
LP
663static void timer_trigger_notify(Unit *u, Unit *other) {
664 Timer *t = TIMER(u);
665 TimerValue *v;
871d7de4 666
3ecaa09b
LP
667 assert(u);
668 assert(other);
871d7de4 669
3ecaa09b
LP
670 if (other->load_state != UNIT_LOADED)
671 return;
871d7de4 672
3ecaa09b
LP
673 /* Reenable all timers that depend on unit state */
674 LIST_FOREACH(value, v, t->values)
675 if (v->base == TIMER_UNIT_ACTIVE ||
676 v->base == TIMER_UNIT_INACTIVE)
677 v->disabled = false;
01f78473 678
3ecaa09b 679 switch (t->state) {
871d7de4 680
3ecaa09b
LP
681 case TIMER_WAITING:
682 case TIMER_ELAPSED:
871d7de4 683
3ecaa09b
LP
684 /* Recalculate sleep time */
685 timer_enter_waiting(t, false);
686 break;
871d7de4 687
3ecaa09b 688 case TIMER_RUNNING:
871d7de4 689
3ecaa09b 690 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
f2341e0a 691 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
871d7de4 692 timer_enter_waiting(t, false);
3ecaa09b
LP
693 }
694 break;
871d7de4 695
3ecaa09b
LP
696 case TIMER_DEAD:
697 case TIMER_FAILED:
698 break;
871d7de4 699
3ecaa09b
LP
700 default:
701 assert_not_reached("Unknown timer state");
871d7de4 702 }
871d7de4
LP
703}
704
fdf20a31 705static void timer_reset_failed(Unit *u) {
5632e374
LP
706 Timer *t = TIMER(u);
707
708 assert(t);
709
fdf20a31 710 if (t->state == TIMER_FAILED)
5632e374
LP
711 timer_set_state(t, TIMER_DEAD);
712
067d72c9 713 t->result = TIMER_SUCCESS;
5632e374
LP
714}
715
8742514c
LP
716static void timer_time_change(Unit *u) {
717 Timer *t = TIMER(u);
718
719 assert(u);
720
721 if (t->state != TIMER_WAITING)
722 return;
723
f2341e0a 724 log_unit_debug(u, "Time change, recalculating next elapse.");
8742514c
LP
725 timer_enter_waiting(t, false);
726}
727
871d7de4 728static const char* const timer_base_table[_TIMER_BASE_MAX] = {
03fae018
LP
729 [TIMER_ACTIVE] = "OnActiveSec",
730 [TIMER_BOOT] = "OnBootSec",
731 [TIMER_STARTUP] = "OnStartupSec",
732 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
36697dc0
LP
733 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
734 [TIMER_CALENDAR] = "OnCalendar"
871d7de4
LP
735};
736
737DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
738
067d72c9
LP
739static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
740 [TIMER_SUCCESS] = "success",
741 [TIMER_FAILURE_RESOURCES] = "resources"
742};
743
744DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
745
87f0e418 746const UnitVTable timer_vtable = {
7d17cfbc 747 .object_size = sizeof(Timer),
718db961 748
f975e971
LP
749 .sections =
750 "Unit\0"
751 "Timer\0"
752 "Install\0",
d8a812d1 753 .private_section = "Timer",
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
718db961 777 .bus_vtable = bus_timer_vtable,
d8a812d1
WC
778 .bus_set_property = bus_timer_set_property,
779
780 .can_transient = true,
5cb5a6ff 781};