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