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