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