]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/timer.c
Update Spanish translation
[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
6e392c9c
IS
270static int timer_enter_waiting_coldplug(Unit *u) {
271 timer_enter_waiting(TIMER(u), false);
272 return 0;
273}
274
275static int timer_coldplug(Unit *u, Hashmap *deferred_work) {
871d7de4
LP
276 Timer *t = TIMER(u);
277
278 assert(t);
279 assert(t->state == TIMER_DEAD);
280
281 if (t->deserialized_state != t->state) {
282
6e392c9c
IS
283 if (t->deserialized_state == TIMER_WAITING) {
284 hashmap_put(deferred_work, u, &timer_enter_waiting_coldplug);
285 timer_set_state(t, TIMER_WAITING);
286 } else
871d7de4
LP
287 timer_set_state(t, t->deserialized_state);
288 }
289
290 return 0;
291}
292
067d72c9 293static void timer_enter_dead(Timer *t, TimerResult f) {
871d7de4
LP
294 assert(t);
295
067d72c9
LP
296 if (f != TIMER_SUCCESS)
297 t->result = f;
871d7de4 298
067d72c9 299 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
871d7de4
LP
300}
301
dedabea4
LP
302static usec_t monotonic_to_boottime(usec_t t) {
303 usec_t a, b;
304
305 if (t <= 0)
306 return 0;
307
308 a = now(CLOCK_BOOTTIME);
309 b = now(CLOCK_MONOTONIC);
310
311 if (t + a > b)
312 return t + a - b;
313 else
314 return 0;
315}
316
871d7de4 317static void timer_enter_waiting(Timer *t, bool initial) {
36697dc0 318 bool found_monotonic = false, found_realtime = false;
dedabea4
LP
319 usec_t ts_realtime, ts_monotonic;
320 usec_t base = 0;
321 TimerValue *v;
871d7de4
LP
322 int r;
323
dedabea4
LP
324 /* If we shall wake the system we use the boottime clock
325 * rather than the monotonic clock. */
326
327 ts_realtime = now(CLOCK_REALTIME);
328 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
329 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
871d7de4
LP
330
331 LIST_FOREACH(value, v, t->values) {
332
333 if (v->disabled)
334 continue;
335
36697dc0 336 if (v->base == TIMER_CALENDAR) {
06642d17
LP
337 usec_t b;
338
339 /* If we know the last time this was
340 * triggered, schedule the job based relative
341 * to that. If we don't just start from
342 * now. */
36697dc0 343
dedabea4 344 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
06642d17
LP
345
346 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
36697dc0
LP
347 if (r < 0)
348 continue;
349
36697dc0
LP
350 if (!found_realtime)
351 t->next_elapse_realtime = v->next_elapse;
10717a1a 352 else
36697dc0 353 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
871d7de4 354
36697dc0 355 found_realtime = true;
871d7de4 356
36697dc0
LP
357 } else {
358 switch (v->base) {
871d7de4 359
36697dc0
LP
360 case TIMER_ACTIVE:
361 if (state_translation_table[t->state] == UNIT_ACTIVE)
362 base = UNIT(t)->inactive_exit_timestamp.monotonic;
363 else
dedabea4 364 base = ts_monotonic;
36697dc0 365 break;
871d7de4 366
36697dc0
LP
367 case TIMER_BOOT:
368 /* CLOCK_MONOTONIC equals the uptime on Linux */
369 base = 0;
370 break;
871d7de4 371
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) {
79008bdd 425 log_unit_debug(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
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
79008bdd 433 log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
dedabea4
LP
434 UNIT(t)->id,
435 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
871d7de4 436
718db961 437 if (t->monotonic_event_source) {
dedabea4 438 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
718db961
LP
439 if (r < 0)
440 goto fail;
441
442 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
443 } else
6a0f1f6d
LP
444 r = sd_event_add_time(
445 UNIT(t)->manager->event,
446 &t->monotonic_event_source,
dedabea4
LP
447 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
448 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
6a0f1f6d 449 timer_dispatch, t);
36697dc0
LP
450 if (r < 0)
451 goto fail;
718db961
LP
452
453 } else if (t->monotonic_event_source) {
718db961 454
06642d17 455 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
718db961
LP
456 if (r < 0)
457 goto fail;
458 }
36697dc0
LP
459
460 if (found_realtime) {
461 char buf[FORMAT_TIMESTAMP_MAX];
79008bdd 462 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 463
718db961
LP
464 if (t->realtime_event_source) {
465 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
466 if (r < 0)
467 goto fail;
468
469 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
470 } else
6a0f1f6d
LP
471 r = sd_event_add_time(
472 UNIT(t)->manager->event,
473 &t->realtime_event_source,
dedabea4 474 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
6a0f1f6d
LP
475 t->next_elapse_realtime, t->accuracy_usec,
476 timer_dispatch, t);
36697dc0
LP
477 if (r < 0)
478 goto fail;
718db961
LP
479
480 } else if (t->realtime_event_source) {
718db961 481
06642d17 482 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
718db961
LP
483 if (r < 0)
484 goto fail;
485 }
871d7de4
LP
486
487 timer_set_state(t, TIMER_WAITING);
488 return;
489
490fail:
31938a85 491 log_unit_warning_errno(UNIT(t)->id, r, "%s failed to enter waiting state: %m", UNIT(t)->id);
067d72c9 492 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
493}
494
495static void timer_enter_running(Timer *t) {
718db961 496 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
871d7de4 497 int r;
398ef8ba 498
871d7de4
LP
499 assert(t);
500
ba3e67a7 501 /* Don't start job if we are supposed to go down */
31afa0a4 502 if (unit_stop_pending(UNIT(t)))
ba3e67a7
LP
503 return;
504
3ecaa09b
LP
505 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
506 JOB_REPLACE, true, &error, NULL);
36697dc0 507 if (r < 0)
871d7de4
LP
508 goto fail;
509
06642d17
LP
510 dual_timestamp_get(&t->last_trigger);
511
472fc28f 512 if (t->stamp_path)
fed1e721 513 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
e41e1943 514
871d7de4
LP
515 timer_set_state(t, TIMER_RUNNING);
516 return;
517
518fail:
79008bdd 519 log_unit_warning(UNIT(t)->id,
66870f90 520 "%s failed to queue unit startup job: %s",
718db961 521 UNIT(t)->id, bus_error_message(&error, r));
067d72c9 522 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
871d7de4
LP
523}
524
525static int timer_start(Unit *u) {
526 Timer *t = TIMER(u);
779042e7 527 TimerValue *v;
871d7de4
LP
528
529 assert(t);
fdf20a31 530 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
01f78473 531
3ecaa09b 532 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
01f78473 533 return -ENOENT;
871d7de4 534
06642d17
LP
535 t->last_trigger = DUAL_TIMESTAMP_NULL;
536
779042e7
MC
537 /* Reenable all timers that depend on unit activation time */
538 LIST_FOREACH(value, v, t->values)
539 if (v->base == TIMER_ACTIVE)
540 v->disabled = false;
541
06642d17
LP
542 if (t->stamp_path) {
543 struct stat st;
544
545 if (stat(t->stamp_path, &st) >= 0)
546 t->last_trigger.realtime = timespec_load(&st.st_atim);
472fc28f
TB
547 else if (errno == ENOENT)
548 /* The timer has never run before,
549 * make sure a stamp file exists.
550 */
46bcf492 551 touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
06642d17
LP
552 }
553
067d72c9 554 t->result = TIMER_SUCCESS;
871d7de4 555 timer_enter_waiting(t, true);
82a2b6bb 556 return 1;
871d7de4
LP
557}
558
559static int timer_stop(Unit *u) {
560 Timer *t = TIMER(u);
561
562 assert(t);
563 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
564
067d72c9 565 timer_enter_dead(t, TIMER_SUCCESS);
82a2b6bb 566 return 1;
871d7de4
LP
567}
568
569static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
570 Timer *t = TIMER(u);
571
572 assert(u);
573 assert(f);
574 assert(fds);
575
576 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
067d72c9 577 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
871d7de4 578
06642d17
LP
579 if (t->last_trigger.realtime > 0)
580 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
581
582 if (t->last_trigger.monotonic > 0)
583 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
584
871d7de4
LP
585 return 0;
586}
587
588static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
589 Timer *t = TIMER(u);
06642d17 590 int r;
871d7de4
LP
591
592 assert(u);
593 assert(key);
594 assert(value);
595 assert(fds);
596
597 if (streq(key, "state")) {
598 TimerState state;
599
36697dc0
LP
600 state = timer_state_from_string(value);
601 if (state < 0)
79008bdd 602 log_unit_debug(u->id, "Failed to parse state value %s", value);
871d7de4
LP
603 else
604 t->deserialized_state = state;
067d72c9
LP
605 } else if (streq(key, "result")) {
606 TimerResult f;
607
608 f = timer_result_from_string(value);
609 if (f < 0)
79008bdd 610 log_unit_debug(u->id, "Failed to parse result value %s", value);
067d72c9
LP
611 else if (f != TIMER_SUCCESS)
612 t->result = f;
06642d17
LP
613 } else if (streq(key, "last-trigger-realtime")) {
614
615 r = safe_atou64(value, &t->last_trigger.realtime);
616 if (r < 0)
79008bdd 617 log_unit_debug(u->id, "Failed to parse last-trigger-realtime value %s", value);
06642d17
LP
618
619 } else if (streq(key, "last-trigger-monotonic")) {
620
621 r = safe_atou64(value, &t->last_trigger.monotonic);
622 if (r < 0)
79008bdd 623 log_unit_debug(u->id, "Failed to parse last-trigger-monotonic value %s", value);
067d72c9 624
871d7de4 625 } else
79008bdd 626 log_unit_debug(u->id, "Unknown serialization key '%s'", key);
871d7de4
LP
627
628 return 0;
034c6ed7
LP
629}
630
44a6b1b6 631_pure_ static UnitActiveState timer_active_state(Unit *u) {
871d7de4
LP
632 assert(u);
633
634 return state_translation_table[TIMER(u)->state];
635}
636
44a6b1b6 637_pure_ static const char *timer_sub_state_to_string(Unit *u) {
871d7de4
LP
638 assert(u);
639
640 return timer_state_to_string(TIMER(u)->state);
641}
642
718db961
LP
643static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
644 Timer *t = TIMER(userdata);
871d7de4
LP
645
646 assert(t);
5cb5a6ff 647
871d7de4 648 if (t->state != TIMER_WAITING)
718db961 649 return 0;
5cb5a6ff 650
79008bdd 651 log_unit_debug(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
871d7de4 652 timer_enter_running(t);
718db961 653 return 0;
5cb5a6ff
LP
654}
655
3ecaa09b
LP
656static void timer_trigger_notify(Unit *u, Unit *other) {
657 Timer *t = TIMER(u);
658 TimerValue *v;
871d7de4 659
3ecaa09b
LP
660 assert(u);
661 assert(other);
871d7de4 662
3ecaa09b
LP
663 if (other->load_state != UNIT_LOADED)
664 return;
871d7de4 665
3ecaa09b
LP
666 /* Reenable all timers that depend on unit state */
667 LIST_FOREACH(value, v, t->values)
668 if (v->base == TIMER_UNIT_ACTIVE ||
669 v->base == TIMER_UNIT_INACTIVE)
670 v->disabled = false;
01f78473 671
3ecaa09b 672 switch (t->state) {
871d7de4 673
3ecaa09b
LP
674 case TIMER_WAITING:
675 case TIMER_ELAPSED:
871d7de4 676
3ecaa09b
LP
677 /* Recalculate sleep time */
678 timer_enter_waiting(t, false);
679 break;
871d7de4 680
3ecaa09b 681 case TIMER_RUNNING:
871d7de4 682
3ecaa09b 683 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
79008bdd 684 log_unit_debug(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
871d7de4 685 timer_enter_waiting(t, false);
3ecaa09b
LP
686 }
687 break;
871d7de4 688
3ecaa09b
LP
689 case TIMER_DEAD:
690 case TIMER_FAILED:
691 break;
871d7de4 692
3ecaa09b
LP
693 default:
694 assert_not_reached("Unknown timer state");
871d7de4 695 }
871d7de4
LP
696}
697
fdf20a31 698static void timer_reset_failed(Unit *u) {
5632e374
LP
699 Timer *t = TIMER(u);
700
701 assert(t);
702
fdf20a31 703 if (t->state == TIMER_FAILED)
5632e374
LP
704 timer_set_state(t, TIMER_DEAD);
705
067d72c9 706 t->result = TIMER_SUCCESS;
5632e374
LP
707}
708
8742514c
LP
709static void timer_time_change(Unit *u) {
710 Timer *t = TIMER(u);
711
712 assert(u);
713
714 if (t->state != TIMER_WAITING)
715 return;
716
79008bdd 717 log_unit_debug(u->id, "%s: time change, recalculating next elapse.", u->id);
8742514c
LP
718 timer_enter_waiting(t, false);
719}
720
871d7de4
LP
721static const char* const timer_state_table[_TIMER_STATE_MAX] = {
722 [TIMER_DEAD] = "dead",
723 [TIMER_WAITING] = "waiting",
724 [TIMER_RUNNING] = "running",
725 [TIMER_ELAPSED] = "elapsed",
fdf20a31 726 [TIMER_FAILED] = "failed"
871d7de4
LP
727};
728
729DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
730
731static const char* const timer_base_table[_TIMER_BASE_MAX] = {
03fae018
LP
732 [TIMER_ACTIVE] = "OnActiveSec",
733 [TIMER_BOOT] = "OnBootSec",
734 [TIMER_STARTUP] = "OnStartupSec",
735 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
36697dc0
LP
736 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
737 [TIMER_CALENDAR] = "OnCalendar"
871d7de4
LP
738};
739
740DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
741
067d72c9
LP
742static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
743 [TIMER_SUCCESS] = "success",
744 [TIMER_FAILURE_RESOURCES] = "resources"
745};
746
747DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
748
87f0e418 749const UnitVTable timer_vtable = {
7d17cfbc 750 .object_size = sizeof(Timer),
718db961 751
f975e971
LP
752 .sections =
753 "Unit\0"
754 "Timer\0"
755 "Install\0",
d8a812d1 756 .private_section = "Timer",
5cb5a6ff 757
871d7de4 758 .init = timer_init,
034c6ed7 759 .done = timer_done,
871d7de4
LP
760 .load = timer_load,
761
762 .coldplug = timer_coldplug,
763
764 .dump = timer_dump,
765
766 .start = timer_start,
767 .stop = timer_stop,
768
769 .serialize = timer_serialize,
770 .deserialize_item = timer_deserialize_item,
771
772 .active_state = timer_active_state,
773 .sub_state_to_string = timer_sub_state_to_string,
774
3ecaa09b
LP
775 .trigger_notify = timer_trigger_notify,
776
fdf20a31 777 .reset_failed = timer_reset_failed,
8742514c 778 .time_change = timer_time_change,
5632e374 779
c4e2ceae 780 .bus_interface = "org.freedesktop.systemd1.Timer",
718db961 781 .bus_vtable = bus_timer_vtable,
d8a812d1
WC
782 .bus_set_property = bus_timer_set_property,
783
784 .can_transient = true,
5cb5a6ff 785};