]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
Add SPDX license identifiers to source files under the LGPL
[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 usec_t base = 0;
358 TimerValue *v;
359 Unit *trigger;
360 int r;
361
362 assert(t);
363
364 trigger = UNIT_TRIGGER(UNIT(t));
365 if (!trigger) {
366 log_unit_error(UNIT(t), "Unit to trigger vanished.");
367 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
368 return;
369 }
370
371 triple_timestamp_get(&ts);
372 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
373
374 LIST_FOREACH(value, v, t->values) {
375
376 if (v->disabled)
377 continue;
378
379 if (v->base == TIMER_CALENDAR) {
380 usec_t b;
381
382 /* If we know the last time this was
383 * triggered, schedule the job based relative
384 * to that. If we don't just start from
385 * now. */
386
387 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts.realtime;
388
389 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
390 if (r < 0)
391 continue;
392
393 if (!found_realtime)
394 t->next_elapse_realtime = v->next_elapse;
395 else
396 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
397
398 found_realtime = true;
399
400 } else {
401
402 switch (v->base) {
403
404 case TIMER_ACTIVE:
405 if (state_translation_table[t->state] == UNIT_ACTIVE)
406 base = UNIT(t)->inactive_exit_timestamp.monotonic;
407 else
408 base = ts.monotonic;
409 break;
410
411 case TIMER_BOOT:
412 if (detect_container() <= 0) {
413 /* CLOCK_MONOTONIC equals the uptime on Linux */
414 base = 0;
415 break;
416 }
417 /* In a container we don't want to include the time the host
418 * was already up when the container started, so count from
419 * our own startup. */
420 /* fall through */
421 case TIMER_STARTUP:
422 base = UNIT(t)->manager->userspace_timestamp.monotonic;
423 break;
424
425 case TIMER_UNIT_ACTIVE:
426 leave_around = true;
427 base = trigger->inactive_exit_timestamp.monotonic;
428
429 if (base <= 0)
430 base = t->last_trigger.monotonic;
431
432 if (base <= 0)
433 continue;
434
435 break;
436
437 case TIMER_UNIT_INACTIVE:
438 leave_around = true;
439 base = trigger->inactive_enter_timestamp.monotonic;
440
441 if (base <= 0)
442 base = t->last_trigger.monotonic;
443
444 if (base <= 0)
445 continue;
446
447 break;
448
449 default:
450 assert_not_reached("Unknown timer base");
451 }
452
453 v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
454
455 if (!initial &&
456 v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
457 IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
458 /* This is a one time trigger, disable it now */
459 v->disabled = true;
460 continue;
461 }
462
463 if (!found_monotonic)
464 t->next_elapse_monotonic_or_boottime = v->next_elapse;
465 else
466 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
467
468 found_monotonic = true;
469 }
470 }
471
472 if (!found_monotonic && !found_realtime) {
473 log_unit_debug(UNIT(t), "Timer is elapsed.");
474 timer_enter_elapsed(t, leave_around);
475 return;
476 }
477
478 if (found_monotonic) {
479 char buf[FORMAT_TIMESPAN_MAX];
480 usec_t left;
481
482 add_random(t, &t->next_elapse_monotonic_or_boottime);
483
484 left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
485 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
486
487 if (t->monotonic_event_source) {
488 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
489 if (r < 0)
490 goto fail;
491
492 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
493 if (r < 0)
494 goto fail;
495 } else {
496
497 r = sd_event_add_time(
498 UNIT(t)->manager->event,
499 &t->monotonic_event_source,
500 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
501 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
502 timer_dispatch, t);
503 if (r < 0)
504 goto fail;
505
506 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
507 }
508
509 } else if (t->monotonic_event_source) {
510
511 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
512 if (r < 0)
513 goto fail;
514 }
515
516 if (found_realtime) {
517 char buf[FORMAT_TIMESTAMP_MAX];
518
519 add_random(t, &t->next_elapse_realtime);
520
521 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
522
523 if (t->realtime_event_source) {
524 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
525 if (r < 0)
526 goto fail;
527
528 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
529 if (r < 0)
530 goto fail;
531 } else {
532 r = sd_event_add_time(
533 UNIT(t)->manager->event,
534 &t->realtime_event_source,
535 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
536 t->next_elapse_realtime, t->accuracy_usec,
537 timer_dispatch, t);
538 if (r < 0)
539 goto fail;
540
541 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
542 }
543
544 } else if (t->realtime_event_source) {
545
546 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
547 if (r < 0)
548 goto fail;
549 }
550
551 timer_set_state(t, TIMER_WAITING);
552 return;
553
554 fail:
555 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
556 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
557 }
558
559 static void timer_enter_running(Timer *t) {
560 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
561 Unit *trigger;
562 int r;
563
564 assert(t);
565
566 /* Don't start job if we are supposed to go down */
567 if (unit_stop_pending(UNIT(t)))
568 return;
569
570 trigger = UNIT_TRIGGER(UNIT(t));
571 if (!trigger) {
572 log_unit_error(UNIT(t), "Unit to trigger vanished.");
573 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
574 return;
575 }
576
577 r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
578 if (r < 0)
579 goto fail;
580
581 dual_timestamp_get(&t->last_trigger);
582
583 if (t->stamp_path)
584 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
585
586 timer_set_state(t, TIMER_RUNNING);
587 return;
588
589 fail:
590 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
591 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
592 }
593
594 static int timer_start(Unit *u) {
595 Timer *t = TIMER(u);
596 TimerValue *v;
597 Unit *trigger;
598 int r;
599
600 assert(t);
601 assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
602
603 trigger = UNIT_TRIGGER(u);
604 if (!trigger || trigger->load_state != UNIT_LOADED) {
605 log_unit_error(u, "Refusing to start, unit to trigger not loaded.");
606 return -ENOENT;
607 }
608
609 r = unit_start_limit_test(u);
610 if (r < 0) {
611 timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
612 return r;
613 }
614
615 r = unit_acquire_invocation_id(u);
616 if (r < 0)
617 return r;
618
619 t->last_trigger = DUAL_TIMESTAMP_NULL;
620
621 /* Reenable all timers that depend on unit activation time */
622 LIST_FOREACH(value, v, t->values)
623 if (v->base == TIMER_ACTIVE)
624 v->disabled = false;
625
626 if (t->stamp_path) {
627 struct stat st;
628
629 if (stat(t->stamp_path, &st) >= 0) {
630 usec_t ft;
631
632 /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
633 * something is wrong with the system clock. */
634
635 ft = timespec_load(&st.st_mtim);
636 if (ft < now(CLOCK_REALTIME))
637 t->last_trigger.realtime = ft;
638 else {
639 char z[FORMAT_TIMESTAMP_MAX];
640
641 log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
642 format_timestamp(z, sizeof(z), ft));
643 }
644
645 } else if (errno == ENOENT)
646 /* The timer has never run before,
647 * make sure a stamp file exists.
648 */
649 (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
650 }
651
652 t->result = TIMER_SUCCESS;
653 timer_enter_waiting(t, true);
654 return 1;
655 }
656
657 static int timer_stop(Unit *u) {
658 Timer *t = TIMER(u);
659
660 assert(t);
661 assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
662
663 timer_enter_dead(t, TIMER_SUCCESS);
664 return 1;
665 }
666
667 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
668 Timer *t = TIMER(u);
669
670 assert(u);
671 assert(f);
672 assert(fds);
673
674 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
675 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
676
677 if (t->last_trigger.realtime > 0)
678 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
679
680 if (t->last_trigger.monotonic > 0)
681 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
682
683 return 0;
684 }
685
686 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
687 Timer *t = TIMER(u);
688 int r;
689
690 assert(u);
691 assert(key);
692 assert(value);
693 assert(fds);
694
695 if (streq(key, "state")) {
696 TimerState state;
697
698 state = timer_state_from_string(value);
699 if (state < 0)
700 log_unit_debug(u, "Failed to parse state value: %s", value);
701 else
702 t->deserialized_state = state;
703 } else if (streq(key, "result")) {
704 TimerResult f;
705
706 f = timer_result_from_string(value);
707 if (f < 0)
708 log_unit_debug(u, "Failed to parse result value: %s", value);
709 else if (f != TIMER_SUCCESS)
710 t->result = f;
711 } else if (streq(key, "last-trigger-realtime")) {
712
713 r = safe_atou64(value, &t->last_trigger.realtime);
714 if (r < 0)
715 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
716
717 } else if (streq(key, "last-trigger-monotonic")) {
718
719 r = safe_atou64(value, &t->last_trigger.monotonic);
720 if (r < 0)
721 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
722
723 } else
724 log_unit_debug(u, "Unknown serialization key: %s", key);
725
726 return 0;
727 }
728
729 _pure_ static UnitActiveState timer_active_state(Unit *u) {
730 assert(u);
731
732 return state_translation_table[TIMER(u)->state];
733 }
734
735 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
736 assert(u);
737
738 return timer_state_to_string(TIMER(u)->state);
739 }
740
741 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
742 Timer *t = TIMER(userdata);
743
744 assert(t);
745
746 if (t->state != TIMER_WAITING)
747 return 0;
748
749 log_unit_debug(UNIT(t), "Timer elapsed.");
750 timer_enter_running(t);
751 return 0;
752 }
753
754 static void timer_trigger_notify(Unit *u, Unit *other) {
755 Timer *t = TIMER(u);
756 TimerValue *v;
757
758 assert(u);
759 assert(other);
760
761 if (other->load_state != UNIT_LOADED)
762 return;
763
764 /* Reenable all timers that depend on unit state */
765 LIST_FOREACH(value, v, t->values)
766 if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
767 v->disabled = false;
768
769 switch (t->state) {
770
771 case TIMER_WAITING:
772 case TIMER_ELAPSED:
773
774 /* Recalculate sleep time */
775 timer_enter_waiting(t, false);
776 break;
777
778 case TIMER_RUNNING:
779
780 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
781 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
782 timer_enter_waiting(t, false);
783 }
784 break;
785
786 case TIMER_DEAD:
787 case TIMER_FAILED:
788 break;
789
790 default:
791 assert_not_reached("Unknown timer state");
792 }
793 }
794
795 static void timer_reset_failed(Unit *u) {
796 Timer *t = TIMER(u);
797
798 assert(t);
799
800 if (t->state == TIMER_FAILED)
801 timer_set_state(t, TIMER_DEAD);
802
803 t->result = TIMER_SUCCESS;
804 }
805
806 static void timer_time_change(Unit *u) {
807 Timer *t = TIMER(u);
808
809 assert(u);
810
811 if (t->state != TIMER_WAITING)
812 return;
813
814 log_unit_debug(u, "Time change, recalculating next elapse.");
815 timer_enter_waiting(t, false);
816 }
817
818 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
819 [TIMER_ACTIVE] = "OnActiveSec",
820 [TIMER_BOOT] = "OnBootSec",
821 [TIMER_STARTUP] = "OnStartupSec",
822 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
823 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
824 [TIMER_CALENDAR] = "OnCalendar"
825 };
826
827 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
828
829 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
830 [TIMER_SUCCESS] = "success",
831 [TIMER_FAILURE_RESOURCES] = "resources",
832 [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
833 };
834
835 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
836
837 const UnitVTable timer_vtable = {
838 .object_size = sizeof(Timer),
839
840 .sections =
841 "Unit\0"
842 "Timer\0"
843 "Install\0",
844 .private_section = "Timer",
845
846 .init = timer_init,
847 .done = timer_done,
848 .load = timer_load,
849
850 .coldplug = timer_coldplug,
851
852 .dump = timer_dump,
853
854 .start = timer_start,
855 .stop = timer_stop,
856
857 .serialize = timer_serialize,
858 .deserialize_item = timer_deserialize_item,
859
860 .active_state = timer_active_state,
861 .sub_state_to_string = timer_sub_state_to_string,
862
863 .trigger_notify = timer_trigger_notify,
864
865 .reset_failed = timer_reset_failed,
866 .time_change = timer_time_change,
867
868 .bus_vtable = bus_timer_vtable,
869 .bus_set_property = bus_timer_set_property,
870
871 .can_transient = true,
872 };