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