]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
Do not format USEC_INFINITY as NULL
[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 #include "bus-error.h"
31 #include "mkdir.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
62 if (v->calendar_spec)
63 calendar_spec_free(v->calendar_spec);
64
65 free(v);
66 }
67 }
68
69 static void timer_done(Unit *u) {
70 Timer *t = TIMER(u);
71
72 assert(t);
73
74 timer_free_values(t);
75
76 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
77 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
78
79 free(t->stamp_path);
80 }
81
82 static int timer_verify(Timer *t) {
83 assert(t);
84
85 if (UNIT(t)->load_state != UNIT_LOADED)
86 return 0;
87
88 if (!t->values) {
89 log_error_unit(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
90 return -EINVAL;
91 }
92
93 return 0;
94 }
95
96 static int timer_add_default_dependencies(Timer *t) {
97 int r;
98 TimerValue *v;
99
100 assert(t);
101
102 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
103 if (r < 0)
104 return r;
105
106 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
107 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
108 if (r < 0)
109 return r;
110
111 LIST_FOREACH(value, v, t->values) {
112 if (v->base == TIMER_CALENDAR) {
113 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
114 if (r < 0)
115 return r;
116 break;
117 }
118 }
119 }
120
121 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
122 }
123
124 static int timer_setup_persistent(Timer *t) {
125 int r;
126
127 assert(t);
128
129 if (!t->persistent)
130 return 0;
131
132 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
133
134 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
135 if (r < 0)
136 return r;
137
138 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
139 } else {
140 const char *e;
141
142 e = getenv("XDG_DATA_HOME");
143 if (e)
144 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
145 else {
146
147 _cleanup_free_ char *h = NULL;
148
149 r = get_home_dir(&h);
150 if (r < 0) {
151 log_error("Failed to determine home directory: %s", strerror(-r));
152 return r;
153 }
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_debug_unit(UNIT(t)->id,
264 "%s changed %s -> %s", UNIT(t)->id,
265 timer_state_to_string(old_state),
266 timer_state_to_string(state));
267
268 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
269 }
270
271 static void timer_enter_waiting(Timer *t, bool initial);
272
273 static int timer_coldplug(Unit *u) {
274 Timer *t = TIMER(u);
275
276 assert(t);
277 assert(t->state == TIMER_DEAD);
278
279 if (t->deserialized_state != t->state) {
280
281 if (t->deserialized_state == TIMER_WAITING)
282 timer_enter_waiting(t, false);
283 else
284 timer_set_state(t, t->deserialized_state);
285 }
286
287 return 0;
288 }
289
290 static void timer_enter_dead(Timer *t, TimerResult f) {
291 assert(t);
292
293 if (f != TIMER_SUCCESS)
294 t->result = f;
295
296 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
297 }
298
299 static usec_t monotonic_to_boottime(usec_t t) {
300 usec_t a, b;
301
302 if (t <= 0)
303 return 0;
304
305 a = now(CLOCK_BOOTTIME);
306 b = now(CLOCK_MONOTONIC);
307
308 if (t + a > b)
309 return t + a - b;
310 else
311 return 0;
312 }
313
314 static void timer_enter_waiting(Timer *t, bool initial) {
315 bool found_monotonic = false, found_realtime = false;
316 usec_t ts_realtime, ts_monotonic;
317 usec_t base = 0;
318 TimerValue *v;
319 int r;
320
321 /* If we shall wake the system we use the boottime clock
322 * rather than the monotonic clock. */
323
324 ts_realtime = now(CLOCK_REALTIME);
325 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
326 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
327
328 LIST_FOREACH(value, v, t->values) {
329
330 if (v->disabled)
331 continue;
332
333 if (v->base == TIMER_CALENDAR) {
334 usec_t b;
335
336 /* If we know the last time this was
337 * triggered, schedule the job based relative
338 * to that. If we don't just start from
339 * now. */
340
341 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
342
343 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
344 if (r < 0)
345 continue;
346
347 if (!found_realtime)
348 t->next_elapse_realtime = v->next_elapse;
349 else
350 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
351
352 found_realtime = true;
353
354 } else {
355 switch (v->base) {
356
357 case TIMER_ACTIVE:
358 if (state_translation_table[t->state] == UNIT_ACTIVE)
359 base = UNIT(t)->inactive_exit_timestamp.monotonic;
360 else
361 base = ts_monotonic;
362 break;
363
364 case TIMER_BOOT:
365 /* CLOCK_MONOTONIC equals the uptime on Linux */
366 base = 0;
367 break;
368
369 case TIMER_STARTUP:
370 base = UNIT(t)->manager->userspace_timestamp.monotonic;
371 break;
372
373 case TIMER_UNIT_ACTIVE:
374
375 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
376
377 if (base <= 0)
378 base = t->last_trigger.monotonic;
379
380 if (base <= 0)
381 continue;
382
383 break;
384
385 case TIMER_UNIT_INACTIVE:
386
387 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
388
389 if (base <= 0)
390 base = t->last_trigger.monotonic;
391
392 if (base <= 0)
393 continue;
394
395 break;
396
397 default:
398 assert_not_reached("Unknown timer base");
399 }
400
401 if (t->wake_system)
402 base = monotonic_to_boottime(base);
403
404 v->next_elapse = base + v->value;
405
406 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
407 /* This is a one time trigger, disable it now */
408 v->disabled = true;
409 continue;
410 }
411
412 if (!found_monotonic)
413 t->next_elapse_monotonic_or_boottime = v->next_elapse;
414 else
415 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
416
417 found_monotonic = true;
418 }
419 }
420
421 if (!found_monotonic && !found_realtime) {
422 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
423 timer_set_state(t, TIMER_ELAPSED);
424 return;
425 }
426
427 if (found_monotonic) {
428 char buf[FORMAT_TIMESPAN_MAX];
429
430 log_debug_unit(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
431 UNIT(t)->id,
432 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
433
434 if (t->monotonic_event_source) {
435 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
436 if (r < 0)
437 goto fail;
438
439 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
440 } else
441 r = sd_event_add_time(
442 UNIT(t)->manager->event,
443 &t->monotonic_event_source,
444 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
445 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
446 timer_dispatch, t);
447 if (r < 0)
448 goto fail;
449
450 } else if (t->monotonic_event_source) {
451
452 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
453 if (r < 0)
454 goto fail;
455 }
456
457 if (found_realtime) {
458 char buf[FORMAT_TIMESTAMP_MAX];
459 log_debug_unit(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
460
461 if (t->realtime_event_source) {
462 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
463 if (r < 0)
464 goto fail;
465
466 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
467 } else
468 r = sd_event_add_time(
469 UNIT(t)->manager->event,
470 &t->realtime_event_source,
471 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
472 t->next_elapse_realtime, t->accuracy_usec,
473 timer_dispatch, t);
474 if (r < 0)
475 goto fail;
476
477 } else if (t->realtime_event_source) {
478
479 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
480 if (r < 0)
481 goto fail;
482 }
483
484 timer_set_state(t, TIMER_WAITING);
485 return;
486
487 fail:
488 log_warning_unit(UNIT(t)->id, "%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
489 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
490 }
491
492 static void timer_enter_running(Timer *t) {
493 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
494 int r;
495
496 assert(t);
497
498 /* Don't start job if we are supposed to go down */
499 if (unit_stop_pending(UNIT(t)))
500 return;
501
502 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
503 JOB_REPLACE, true, &error, NULL);
504 if (r < 0)
505 goto fail;
506
507 dual_timestamp_get(&t->last_trigger);
508
509 if (t->stamp_path)
510 touch_file(t->stamp_path, true, t->last_trigger.realtime, (uid_t) -1, (gid_t) -1, 0);
511
512 timer_set_state(t, TIMER_RUNNING);
513 return;
514
515 fail:
516 log_warning_unit(UNIT(t)->id,
517 "%s failed to queue unit startup job: %s",
518 UNIT(t)->id, bus_error_message(&error, r));
519 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
520 }
521
522 static int timer_start(Unit *u) {
523 Timer *t = TIMER(u);
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 if (t->stamp_path) {
534 struct stat st;
535
536 if (stat(t->stamp_path, &st) >= 0)
537 t->last_trigger.realtime = timespec_load(&st.st_atim);
538 else if (errno == ENOENT)
539 /* The timer has never run before,
540 * make sure a stamp file exists.
541 */
542 touch_file(t->stamp_path, true, (usec_t) -1, (uid_t) -1, (gid_t) -1, 0);
543 }
544
545 t->result = TIMER_SUCCESS;
546 timer_enter_waiting(t, true);
547 return 0;
548 }
549
550 static int timer_stop(Unit *u) {
551 Timer *t = TIMER(u);
552
553 assert(t);
554 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
555
556 timer_enter_dead(t, TIMER_SUCCESS);
557 return 0;
558 }
559
560 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
561 Timer *t = TIMER(u);
562
563 assert(u);
564 assert(f);
565 assert(fds);
566
567 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
568 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
569
570 if (t->last_trigger.realtime > 0)
571 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
572
573 if (t->last_trigger.monotonic > 0)
574 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
575
576 return 0;
577 }
578
579 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
580 Timer *t = TIMER(u);
581 int r;
582
583 assert(u);
584 assert(key);
585 assert(value);
586 assert(fds);
587
588 if (streq(key, "state")) {
589 TimerState state;
590
591 state = timer_state_from_string(value);
592 if (state < 0)
593 log_debug_unit(u->id, "Failed to parse state value %s", value);
594 else
595 t->deserialized_state = state;
596 } else if (streq(key, "result")) {
597 TimerResult f;
598
599 f = timer_result_from_string(value);
600 if (f < 0)
601 log_debug_unit(u->id, "Failed to parse result value %s", value);
602 else if (f != TIMER_SUCCESS)
603 t->result = f;
604 } else if (streq(key, "last-trigger-realtime")) {
605
606 r = safe_atou64(value, &t->last_trigger.realtime);
607 if (r < 0)
608 log_debug_unit(u->id, "Failed to parse last-trigger-realtime value %s", value);
609
610 } else if (streq(key, "last-trigger-monotonic")) {
611
612 r = safe_atou64(value, &t->last_trigger.monotonic);
613 if (r < 0)
614 log_debug_unit(u->id, "Failed to parse last-trigger-monotonic value %s", value);
615
616 } else
617 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
618
619 return 0;
620 }
621
622 _pure_ static UnitActiveState timer_active_state(Unit *u) {
623 assert(u);
624
625 return state_translation_table[TIMER(u)->state];
626 }
627
628 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
629 assert(u);
630
631 return timer_state_to_string(TIMER(u)->state);
632 }
633
634 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
635 Timer *t = TIMER(userdata);
636
637 assert(t);
638
639 if (t->state != TIMER_WAITING)
640 return 0;
641
642 log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
643 timer_enter_running(t);
644 return 0;
645 }
646
647 static void timer_trigger_notify(Unit *u, Unit *other) {
648 Timer *t = TIMER(u);
649 TimerValue *v;
650
651 assert(u);
652 assert(other);
653
654 if (other->load_state != UNIT_LOADED)
655 return;
656
657 /* Reenable all timers that depend on unit state */
658 LIST_FOREACH(value, v, t->values)
659 if (v->base == TIMER_UNIT_ACTIVE ||
660 v->base == TIMER_UNIT_INACTIVE)
661 v->disabled = false;
662
663 switch (t->state) {
664
665 case TIMER_WAITING:
666 case TIMER_ELAPSED:
667
668 /* Recalculate sleep time */
669 timer_enter_waiting(t, false);
670 break;
671
672 case TIMER_RUNNING:
673
674 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
675 log_debug_unit(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
676 timer_enter_waiting(t, false);
677 }
678 break;
679
680 case TIMER_DEAD:
681 case TIMER_FAILED:
682 break;
683
684 default:
685 assert_not_reached("Unknown timer state");
686 }
687 }
688
689 static void timer_reset_failed(Unit *u) {
690 Timer *t = TIMER(u);
691
692 assert(t);
693
694 if (t->state == TIMER_FAILED)
695 timer_set_state(t, TIMER_DEAD);
696
697 t->result = TIMER_SUCCESS;
698 }
699
700 static void timer_time_change(Unit *u) {
701 Timer *t = TIMER(u);
702
703 assert(u);
704
705 if (t->state != TIMER_WAITING)
706 return;
707
708 log_debug_unit(u->id, "%s: time change, recalculating next elapse.", u->id);
709 timer_enter_waiting(t, false);
710 }
711
712 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
713 [TIMER_DEAD] = "dead",
714 [TIMER_WAITING] = "waiting",
715 [TIMER_RUNNING] = "running",
716 [TIMER_ELAPSED] = "elapsed",
717 [TIMER_FAILED] = "failed"
718 };
719
720 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
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
748 .init = timer_init,
749 .done = timer_done,
750 .load = timer_load,
751
752 .coldplug = timer_coldplug,
753
754 .dump = timer_dump,
755
756 .start = timer_start,
757 .stop = timer_stop,
758
759 .serialize = timer_serialize,
760 .deserialize_item = timer_deserialize_item,
761
762 .active_state = timer_active_state,
763 .sub_state_to_string = timer_sub_state_to_string,
764
765 .trigger_notify = timer_trigger_notify,
766
767 .reset_failed = timer_reset_failed,
768 .time_change = timer_time_change,
769
770 .bus_interface = "org.freedesktop.systemd1.Timer",
771 .bus_vtable = bus_timer_vtable,
772 };