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