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