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