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