]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
Merge pull request #8106 from dqminh/route-expires-kernel
[thirdparty/systemd.git] / src / core / timer.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22
23 #include "alloc-util.h"
24 #include "bus-error.h"
25 #include "bus-util.h"
26 #include "dbus-timer.h"
27 #include "fs-util.h"
28 #include "parse-util.h"
29 #include "random-util.h"
30 #include "special.h"
31 #include "string-table.h"
32 #include "string-util.h"
33 #include "timer.h"
34 #include "unit-name.h"
35 #include "unit.h"
36 #include "user-util.h"
37 #include "virt.h"
38
39 static 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,
44 [TIMER_FAILED] = UNIT_FAILED
45 };
46
47 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
48
49 static void timer_init(Unit *u) {
50 Timer *t = TIMER(u);
51
52 assert(u);
53 assert(u->load_state == UNIT_STUB);
54
55 t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
56 t->next_elapse_realtime = USEC_INFINITY;
57 t->accuracy_usec = u->manager->default_timer_accuracy_usec;
58 t->remain_after_elapse = true;
59 }
60
61 void timer_free_values(Timer *t) {
62 TimerValue *v;
63
64 assert(t);
65
66 while ((v = t->values)) {
67 LIST_REMOVE(value, t->values, v);
68 calendar_spec_free(v->calendar_spec);
69 free(v);
70 }
71 }
72
73 static void timer_done(Unit *u) {
74 Timer *t = TIMER(u);
75
76 assert(t);
77
78 timer_free_values(t);
79
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);
82
83 free(t->stamp_path);
84 }
85
86 static int timer_verify(Timer *t) {
87 assert(t);
88
89 if (UNIT(t)->load_state != UNIT_LOADED)
90 return 0;
91
92 if (!t->values) {
93 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
94 return -EINVAL;
95 }
96
97 return 0;
98 }
99
100 static int timer_add_default_dependencies(Timer *t) {
101 int r;
102 TimerValue *v;
103
104 assert(t);
105
106 if (!UNIT(t)->default_dependencies)
107 return 0;
108
109 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
110 if (r < 0)
111 return r;
112
113 if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
114 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
115 if (r < 0)
116 return r;
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, UNIT_DEPENDENCY_DEFAULT);
121 if (r < 0)
122 return r;
123 break;
124 }
125 }
126 }
127
128 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
129 }
130
131 static int timer_add_trigger_dependencies(Timer *t) {
132 Unit *x;
133 int r;
134
135 assert(t);
136
137 if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS]))
138 return 0;
139
140 r = unit_load_related_unit(UNIT(t), ".service", &x);
141 if (r < 0)
142 return r;
143
144 return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
145 }
146
147 static int timer_setup_persistent(Timer *t) {
148 int r;
149
150 assert(t);
151
152 if (!t->persistent)
153 return 0;
154
155 if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
156
157 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE);
158 if (r < 0)
159 return r;
160
161 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
162 } else {
163 const char *e;
164
165 e = getenv("XDG_DATA_HOME");
166 if (e)
167 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id);
168 else {
169
170 _cleanup_free_ char *h = NULL;
171
172 r = get_home_dir(&h);
173 if (r < 0)
174 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
175
176 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id);
177 }
178 }
179
180 if (!t->stamp_path)
181 return log_oom();
182
183 return 0;
184 }
185
186 static int timer_load(Unit *u) {
187 Timer *t = TIMER(u);
188 int r;
189
190 assert(u);
191 assert(u->load_state == UNIT_STUB);
192
193 r = unit_load_fragment_and_dropin(u);
194 if (r < 0)
195 return r;
196
197 if (u->load_state == UNIT_LOADED) {
198
199 r = timer_add_trigger_dependencies(t);
200 if (r < 0)
201 return r;
202
203 r = timer_setup_persistent(t);
204 if (r < 0)
205 return r;
206
207 r = timer_add_default_dependencies(t);
208 if (r < 0)
209 return r;
210 }
211
212 return timer_verify(t);
213 }
214
215 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
216 char buf[FORMAT_TIMESPAN_MAX];
217 Timer *t = TIMER(u);
218 Unit *trigger;
219 TimerValue *v;
220
221 trigger = UNIT_TRIGGER(u);
222
223 fprintf(f,
224 "%sTimer State: %s\n"
225 "%sResult: %s\n"
226 "%sUnit: %s\n"
227 "%sPersistent: %s\n"
228 "%sWakeSystem: %s\n"
229 "%sAccuracy: %s\n"
230 "%sRemainAfterElapse: %s\n",
231 prefix, timer_state_to_string(t->state),
232 prefix, timer_result_to_string(t->result),
233 prefix, trigger ? trigger->id : "n/a",
234 prefix, yes_no(t->persistent),
235 prefix, yes_no(t->wake_system),
236 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
237 prefix, yes_no(t->remain_after_elapse));
238
239 LIST_FOREACH(value, v, t->values) {
240
241 if (v->base == TIMER_CALENDAR) {
242 _cleanup_free_ char *p = NULL;
243
244 (void) calendar_spec_to_string(v->calendar_spec, &p);
245
246 fprintf(f,
247 "%s%s: %s\n",
248 prefix,
249 timer_base_to_string(v->base),
250 strna(p));
251 } else {
252 char timespan1[FORMAT_TIMESPAN_MAX];
253
254 fprintf(f,
255 "%s%s: %s\n",
256 prefix,
257 timer_base_to_string(v->base),
258 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
259 }
260 }
261 }
262
263 static void timer_set_state(Timer *t, TimerState state) {
264 TimerState old_state;
265 assert(t);
266
267 old_state = t->state;
268 t->state = state;
269
270 if (state != TIMER_WAITING) {
271 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
272 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
273 t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
274 t->next_elapse_realtime = USEC_INFINITY;
275 }
276
277 if (state != old_state)
278 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
279
280 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
281 }
282
283 static void timer_enter_waiting(Timer *t, bool initial);
284
285 static int timer_coldplug(Unit *u) {
286 Timer *t = TIMER(u);
287
288 assert(t);
289 assert(t->state == TIMER_DEAD);
290
291 if (t->deserialized_state == t->state)
292 return 0;
293
294 if (t->deserialized_state == TIMER_WAITING)
295 timer_enter_waiting(t, false);
296 else
297 timer_set_state(t, t->deserialized_state);
298
299 return 0;
300 }
301
302 static void timer_enter_dead(Timer *t, TimerResult f) {
303 assert(t);
304
305 if (t->result == TIMER_SUCCESS)
306 t->result = f;
307
308 if (t->result != TIMER_SUCCESS)
309 log_unit_warning(UNIT(t), "Failed with result '%s'.", timer_result_to_string(t->result));
310
311 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
312 }
313
314 static void timer_enter_elapsed(Timer *t, bool leave_around) {
315 assert(t);
316
317 /* If a unit is marked with RemainAfterElapse=yes we leave it
318 * around even after it elapsed once, so that starting it
319 * later again does not necessarily mean immediate
320 * retriggering. We unconditionally leave units with
321 * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
322 * since they might be restarted automatically at any time
323 * later on. */
324
325 if (t->remain_after_elapse || leave_around)
326 timer_set_state(t, TIMER_ELAPSED);
327 else
328 timer_enter_dead(t, TIMER_SUCCESS);
329 }
330
331 static void add_random(Timer *t, usec_t *v) {
332 char s[FORMAT_TIMESPAN_MAX];
333 usec_t add;
334
335 assert(t);
336 assert(v);
337
338 if (t->random_usec == 0)
339 return;
340 if (*v == USEC_INFINITY)
341 return;
342
343 add = random_u64() % t->random_usec;
344
345 if (*v + add < *v) /* overflow */
346 *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
347 else
348 *v += add;
349
350 log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
351 }
352
353 static void timer_enter_waiting(Timer *t, bool initial) {
354 bool found_monotonic = false, found_realtime = false;
355 bool leave_around = false;
356 triple_timestamp ts;
357 TimerValue *v;
358 Unit *trigger;
359 int r;
360
361 assert(t);
362
363 trigger = UNIT_TRIGGER(UNIT(t));
364 if (!trigger) {
365 log_unit_error(UNIT(t), "Unit to trigger vanished.");
366 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
367 return;
368 }
369
370 triple_timestamp_get(&ts);
371 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
372
373 LIST_FOREACH(value, v, t->values) {
374 if (v->disabled)
375 continue;
376
377 if (v->base == TIMER_CALENDAR) {
378 usec_t b;
379
380 /* If we know the last time this was
381 * triggered, schedule the job based relative
382 * to that. If we don't, just start from
383 * the activation time. */
384
385 if (t->last_trigger.realtime > 0)
386 b = t->last_trigger.realtime;
387 else {
388 if (state_translation_table[t->state] == UNIT_ACTIVE)
389 b = UNIT(t)->inactive_exit_timestamp.realtime;
390 else
391 b = ts.realtime;
392 }
393
394 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
395 if (r < 0)
396 continue;
397
398 if (!found_realtime)
399 t->next_elapse_realtime = v->next_elapse;
400 else
401 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
402
403 found_realtime = true;
404
405 } else {
406 usec_t base;
407
408 switch (v->base) {
409
410 case TIMER_ACTIVE:
411 if (state_translation_table[t->state] == UNIT_ACTIVE)
412 base = UNIT(t)->inactive_exit_timestamp.monotonic;
413 else
414 base = ts.monotonic;
415 break;
416
417 case TIMER_BOOT:
418 if (detect_container() <= 0) {
419 /* CLOCK_MONOTONIC equals the uptime on Linux */
420 base = 0;
421 break;
422 }
423 /* In a container we don't want to include the time the host
424 * was already up when the container started, so count from
425 * our own startup. */
426 _fallthrough_;
427 case TIMER_STARTUP:
428 base = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
429 break;
430
431 case TIMER_UNIT_ACTIVE:
432 leave_around = true;
433 base = trigger->inactive_exit_timestamp.monotonic;
434
435 if (base <= 0)
436 base = t->last_trigger.monotonic;
437
438 if (base <= 0)
439 continue;
440 base = MAX(base, t->last_trigger.monotonic);
441
442 break;
443
444 case TIMER_UNIT_INACTIVE:
445 leave_around = true;
446 base = trigger->inactive_enter_timestamp.monotonic;
447
448 if (base <= 0)
449 base = t->last_trigger.monotonic;
450
451 if (base <= 0)
452 continue;
453 base = MAX(base, t->last_trigger.monotonic);
454
455 break;
456
457 default:
458 assert_not_reached("Unknown timer base");
459 }
460
461 v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
462
463 if (!initial &&
464 v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
465 IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
466 /* This is a one time trigger, disable it now */
467 v->disabled = true;
468 continue;
469 }
470
471 if (!found_monotonic)
472 t->next_elapse_monotonic_or_boottime = v->next_elapse;
473 else
474 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
475
476 found_monotonic = true;
477 }
478 }
479
480 if (!found_monotonic && !found_realtime) {
481 log_unit_debug(UNIT(t), "Timer is elapsed.");
482 timer_enter_elapsed(t, leave_around);
483 return;
484 }
485
486 if (found_monotonic) {
487 char buf[FORMAT_TIMESPAN_MAX];
488 usec_t left;
489
490 add_random(t, &t->next_elapse_monotonic_or_boottime);
491
492 left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
493 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
494
495 if (t->monotonic_event_source) {
496 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
497 if (r < 0)
498 goto fail;
499
500 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
501 if (r < 0)
502 goto fail;
503 } else {
504
505 r = sd_event_add_time(
506 UNIT(t)->manager->event,
507 &t->monotonic_event_source,
508 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
509 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
510 timer_dispatch, t);
511 if (r < 0)
512 goto fail;
513
514 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
515 }
516
517 } else if (t->monotonic_event_source) {
518
519 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
520 if (r < 0)
521 goto fail;
522 }
523
524 if (found_realtime) {
525 char buf[FORMAT_TIMESTAMP_MAX];
526
527 add_random(t, &t->next_elapse_realtime);
528
529 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
530
531 if (t->realtime_event_source) {
532 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
533 if (r < 0)
534 goto fail;
535
536 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
537 if (r < 0)
538 goto fail;
539 } else {
540 r = sd_event_add_time(
541 UNIT(t)->manager->event,
542 &t->realtime_event_source,
543 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
544 t->next_elapse_realtime, t->accuracy_usec,
545 timer_dispatch, t);
546 if (r < 0)
547 goto fail;
548
549 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
550 }
551
552 } else if (t->realtime_event_source) {
553
554 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
555 if (r < 0)
556 goto fail;
557 }
558
559 timer_set_state(t, TIMER_WAITING);
560 return;
561
562 fail:
563 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
564 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
565 }
566
567 static void timer_enter_running(Timer *t) {
568 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
569 Unit *trigger;
570 int r;
571
572 assert(t);
573
574 /* Don't start job if we are supposed to go down */
575 if (unit_stop_pending(UNIT(t)))
576 return;
577
578 trigger = UNIT_TRIGGER(UNIT(t));
579 if (!trigger) {
580 log_unit_error(UNIT(t), "Unit to trigger vanished.");
581 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
582 return;
583 }
584
585 r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
586 if (r < 0)
587 goto fail;
588
589 dual_timestamp_get(&t->last_trigger);
590
591 if (t->stamp_path)
592 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
593
594 timer_set_state(t, TIMER_RUNNING);
595 return;
596
597 fail:
598 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
599 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
600 }
601
602 static int timer_start(Unit *u) {
603 Timer *t = TIMER(u);
604 TimerValue *v;
605 Unit *trigger;
606 int r;
607
608 assert(t);
609 assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
610
611 trigger = UNIT_TRIGGER(u);
612 if (!trigger || trigger->load_state != UNIT_LOADED) {
613 log_unit_error(u, "Refusing to start, unit to trigger not loaded.");
614 return -ENOENT;
615 }
616
617 r = unit_start_limit_test(u);
618 if (r < 0) {
619 timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
620 return r;
621 }
622
623 r = unit_acquire_invocation_id(u);
624 if (r < 0)
625 return r;
626
627 t->last_trigger = DUAL_TIMESTAMP_NULL;
628
629 /* Reenable all timers that depend on unit activation time */
630 LIST_FOREACH(value, v, t->values)
631 if (v->base == TIMER_ACTIVE)
632 v->disabled = false;
633
634 if (t->stamp_path) {
635 struct stat st;
636
637 if (stat(t->stamp_path, &st) >= 0) {
638 usec_t ft;
639
640 /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
641 * something is wrong with the system clock. */
642
643 ft = timespec_load(&st.st_mtim);
644 if (ft < now(CLOCK_REALTIME))
645 t->last_trigger.realtime = ft;
646 else {
647 char z[FORMAT_TIMESTAMP_MAX];
648
649 log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
650 format_timestamp(z, sizeof(z), ft));
651 }
652
653 } else if (errno == ENOENT)
654 /* The timer has never run before,
655 * make sure a stamp file exists.
656 */
657 (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
658 }
659
660 t->result = TIMER_SUCCESS;
661 timer_enter_waiting(t, true);
662 return 1;
663 }
664
665 static int timer_stop(Unit *u) {
666 Timer *t = TIMER(u);
667
668 assert(t);
669 assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
670
671 timer_enter_dead(t, TIMER_SUCCESS);
672 return 1;
673 }
674
675 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
676 Timer *t = TIMER(u);
677
678 assert(u);
679 assert(f);
680 assert(fds);
681
682 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
683 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
684
685 if (t->last_trigger.realtime > 0)
686 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
687
688 if (t->last_trigger.monotonic > 0)
689 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
690
691 return 0;
692 }
693
694 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
695 Timer *t = TIMER(u);
696 int r;
697
698 assert(u);
699 assert(key);
700 assert(value);
701 assert(fds);
702
703 if (streq(key, "state")) {
704 TimerState state;
705
706 state = timer_state_from_string(value);
707 if (state < 0)
708 log_unit_debug(u, "Failed to parse state value: %s", value);
709 else
710 t->deserialized_state = state;
711 } else if (streq(key, "result")) {
712 TimerResult f;
713
714 f = timer_result_from_string(value);
715 if (f < 0)
716 log_unit_debug(u, "Failed to parse result value: %s", value);
717 else if (f != TIMER_SUCCESS)
718 t->result = f;
719 } else if (streq(key, "last-trigger-realtime")) {
720
721 r = safe_atou64(value, &t->last_trigger.realtime);
722 if (r < 0)
723 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
724
725 } else if (streq(key, "last-trigger-monotonic")) {
726
727 r = safe_atou64(value, &t->last_trigger.monotonic);
728 if (r < 0)
729 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
730
731 } else
732 log_unit_debug(u, "Unknown serialization key: %s", key);
733
734 return 0;
735 }
736
737 _pure_ static UnitActiveState timer_active_state(Unit *u) {
738 assert(u);
739
740 return state_translation_table[TIMER(u)->state];
741 }
742
743 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
744 assert(u);
745
746 return timer_state_to_string(TIMER(u)->state);
747 }
748
749 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
750 Timer *t = TIMER(userdata);
751
752 assert(t);
753
754 if (t->state != TIMER_WAITING)
755 return 0;
756
757 log_unit_debug(UNIT(t), "Timer elapsed.");
758 timer_enter_running(t);
759 return 0;
760 }
761
762 static void timer_trigger_notify(Unit *u, Unit *other) {
763 Timer *t = TIMER(u);
764 TimerValue *v;
765
766 assert(u);
767 assert(other);
768
769 if (other->load_state != UNIT_LOADED)
770 return;
771
772 /* Reenable all timers that depend on unit state */
773 LIST_FOREACH(value, v, t->values)
774 if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
775 v->disabled = false;
776
777 switch (t->state) {
778
779 case TIMER_WAITING:
780 case TIMER_ELAPSED:
781
782 /* Recalculate sleep time */
783 timer_enter_waiting(t, false);
784 break;
785
786 case TIMER_RUNNING:
787
788 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
789 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
790 timer_enter_waiting(t, false);
791 }
792 break;
793
794 case TIMER_DEAD:
795 case TIMER_FAILED:
796 break;
797
798 default:
799 assert_not_reached("Unknown timer state");
800 }
801 }
802
803 static void timer_reset_failed(Unit *u) {
804 Timer *t = TIMER(u);
805
806 assert(t);
807
808 if (t->state == TIMER_FAILED)
809 timer_set_state(t, TIMER_DEAD);
810
811 t->result = TIMER_SUCCESS;
812 }
813
814 static void timer_time_change(Unit *u) {
815 Timer *t = TIMER(u);
816 usec_t ts;
817
818 assert(u);
819
820 if (t->state != TIMER_WAITING)
821 return;
822
823 /* If we appear to have triggered in the future, the system clock must
824 * have been set backwards. So let's rewind our own clock and allow
825 * the future trigger(s) to happen again :). Exactly the same as when
826 * you start a timer unit with Persistent=yes. */
827 ts = now(CLOCK_REALTIME);
828 if (t->last_trigger.realtime > ts)
829 t->last_trigger.realtime = ts;
830
831 log_unit_debug(u, "Time change, recalculating next elapse.");
832 timer_enter_waiting(t, false);
833 }
834
835 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
836 [TIMER_ACTIVE] = "OnActiveSec",
837 [TIMER_BOOT] = "OnBootSec",
838 [TIMER_STARTUP] = "OnStartupSec",
839 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
840 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
841 [TIMER_CALENDAR] = "OnCalendar"
842 };
843
844 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
845
846 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
847 [TIMER_SUCCESS] = "success",
848 [TIMER_FAILURE_RESOURCES] = "resources",
849 [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
850 };
851
852 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
853
854 const UnitVTable timer_vtable = {
855 .object_size = sizeof(Timer),
856
857 .sections =
858 "Unit\0"
859 "Timer\0"
860 "Install\0",
861 .private_section = "Timer",
862
863 .init = timer_init,
864 .done = timer_done,
865 .load = timer_load,
866
867 .coldplug = timer_coldplug,
868
869 .dump = timer_dump,
870
871 .start = timer_start,
872 .stop = timer_stop,
873
874 .serialize = timer_serialize,
875 .deserialize_item = timer_deserialize_item,
876
877 .active_state = timer_active_state,
878 .sub_state_to_string = timer_sub_state_to_string,
879
880 .trigger_notify = timer_trigger_notify,
881
882 .reset_failed = timer_reset_failed,
883 .time_change = timer_time_change,
884
885 .bus_vtable = bus_timer_vtable,
886 .bus_set_property = bus_timer_set_property,
887
888 .can_transient = true,
889 };