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