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