]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
timer: name the stamp file consistently
[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 int timer_setup_persistent(Timer *t) {
115 int r;
116
117 assert(t);
118
119 if (!t->persistent)
120 return 0;
121
122 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
123
124 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
125 if (r < 0)
126 return r;
127
128 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
129 } else {
130 const char *e;
131
132 e = getenv("XDG_DATA_HOME");
133 if (e)
134 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
135 else {
136
137 _cleanup_free_ char *h = NULL;
138
139 r = get_home_dir(&h);
140 if (r < 0) {
141 log_error("Failed to determine home directory: %s", strerror(-r));
142 return r;
143 }
144
145 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
146 }
147 }
148
149 if (!t->stamp_path)
150 return log_oom();
151
152 return 0;
153 }
154
155 static int timer_load(Unit *u) {
156 Timer *t = TIMER(u);
157 int r;
158
159 assert(u);
160 assert(u->load_state == UNIT_STUB);
161
162 r = unit_load_fragment_and_dropin(u);
163 if (r < 0)
164 return r;
165
166 if (u->load_state == UNIT_LOADED) {
167
168 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
169 Unit *x;
170
171 r = unit_load_related_unit(u, ".service", &x);
172 if (r < 0)
173 return r;
174
175 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
176 if (r < 0)
177 return r;
178 }
179
180 r = timer_setup_persistent(t);
181 if (r < 0)
182 return r;
183
184 if (u->default_dependencies) {
185 r = timer_add_default_dependencies(t);
186 if (r < 0)
187 return r;
188 }
189 }
190
191 return timer_verify(t);
192 }
193
194 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
195 char buf[FORMAT_TIMESPAN_MAX];
196 Timer *t = TIMER(u);
197 Unit *trigger;
198 TimerValue *v;
199
200 trigger = UNIT_TRIGGER(u);
201
202 fprintf(f,
203 "%sTimer State: %s\n"
204 "%sResult: %s\n"
205 "%sUnit: %s\n"
206 "%sPersistent: %s\n"
207 "%sWakeSystem: %s\n"
208 "%sAccuracy: %s\n",
209 prefix, timer_state_to_string(t->state),
210 prefix, timer_result_to_string(t->result),
211 prefix, trigger ? trigger->id : "n/a",
212 prefix, yes_no(t->persistent),
213 prefix, yes_no(t->wake_system),
214 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
215
216 LIST_FOREACH(value, v, t->values) {
217
218 if (v->base == TIMER_CALENDAR) {
219 _cleanup_free_ char *p = NULL;
220
221 calendar_spec_to_string(v->calendar_spec, &p);
222
223 fprintf(f,
224 "%s%s: %s\n",
225 prefix,
226 timer_base_to_string(v->base),
227 strna(p));
228 } else {
229 char timespan1[FORMAT_TIMESPAN_MAX];
230
231 fprintf(f,
232 "%s%s: %s\n",
233 prefix,
234 timer_base_to_string(v->base),
235 strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0)));
236 }
237 }
238 }
239
240 static void timer_set_state(Timer *t, TimerState state) {
241 TimerState old_state;
242 assert(t);
243
244 old_state = t->state;
245 t->state = state;
246
247 if (state != TIMER_WAITING) {
248 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
249 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
250 }
251
252 if (state != old_state)
253 log_debug_unit(UNIT(t)->id,
254 "%s changed %s -> %s", UNIT(t)->id,
255 timer_state_to_string(old_state),
256 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_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
413 timer_set_state(t, TIMER_ELAPSED);
414 return;
415 }
416
417 if (found_monotonic) {
418 char buf[FORMAT_TIMESPAN_MAX];
419
420 log_debug_unit(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
421 UNIT(t)->id,
422 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
423
424 if (t->monotonic_event_source) {
425 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
426 if (r < 0)
427 goto fail;
428
429 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
430 } else
431 r = sd_event_add_time(
432 UNIT(t)->manager->event,
433 &t->monotonic_event_source,
434 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
435 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
436 timer_dispatch, t);
437 if (r < 0)
438 goto fail;
439
440 } else if (t->monotonic_event_source) {
441
442 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
443 if (r < 0)
444 goto fail;
445 }
446
447 if (found_realtime) {
448 char buf[FORMAT_TIMESTAMP_MAX];
449 log_debug_unit(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
450
451 if (t->realtime_event_source) {
452 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
453 if (r < 0)
454 goto fail;
455
456 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
457 } else
458 r = sd_event_add_time(
459 UNIT(t)->manager->event,
460 &t->realtime_event_source,
461 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
462 t->next_elapse_realtime, t->accuracy_usec,
463 timer_dispatch, t);
464 if (r < 0)
465 goto fail;
466
467 } else if (t->realtime_event_source) {
468
469 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
470 if (r < 0)
471 goto fail;
472 }
473
474 timer_set_state(t, TIMER_WAITING);
475 return;
476
477 fail:
478 log_warning_unit(UNIT(t)->id, "%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
479 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
480 }
481
482 static void timer_enter_running(Timer *t) {
483 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
484 int r;
485
486 assert(t);
487
488 /* Don't start job if we are supposed to go down */
489 if (unit_stop_pending(UNIT(t)))
490 return;
491
492 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
493 JOB_REPLACE, true, &error, NULL);
494 if (r < 0)
495 goto fail;
496
497 dual_timestamp_get(&t->last_trigger);
498
499 if (t->stamp_path)
500 touch_file(t->stamp_path, true, t->last_trigger.realtime, (uid_t) -1, (gid_t) -1, 0);
501
502 timer_set_state(t, TIMER_RUNNING);
503 return;
504
505 fail:
506 log_warning_unit(UNIT(t)->id,
507 "%s failed to queue unit startup job: %s",
508 UNIT(t)->id, bus_error_message(&error, r));
509 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
510 }
511
512 static int timer_start(Unit *u) {
513 Timer *t = TIMER(u);
514
515 assert(t);
516 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
517
518 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
519 return -ENOENT;
520
521 t->last_trigger = DUAL_TIMESTAMP_NULL;
522
523 if (t->stamp_path) {
524 struct stat st;
525
526 if (stat(t->stamp_path, &st) >= 0)
527 t->last_trigger.realtime = timespec_load(&st.st_atim);
528 else if (errno == ENOENT)
529 /* The timer has never run before,
530 * make sure a stamp file exists.
531 */
532 touch_file(t->stamp_path, true, (usec_t) -1, (uid_t) -1, (gid_t) -1, 0);
533 }
534
535 t->result = TIMER_SUCCESS;
536 timer_enter_waiting(t, true);
537 return 0;
538 }
539
540 static int timer_stop(Unit *u) {
541 Timer *t = TIMER(u);
542
543 assert(t);
544 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
545
546 timer_enter_dead(t, TIMER_SUCCESS);
547 return 0;
548 }
549
550 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
551 Timer *t = TIMER(u);
552
553 assert(u);
554 assert(f);
555 assert(fds);
556
557 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
558 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
559
560 if (t->last_trigger.realtime > 0)
561 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
562
563 if (t->last_trigger.monotonic > 0)
564 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
565
566 return 0;
567 }
568
569 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
570 Timer *t = TIMER(u);
571 int r;
572
573 assert(u);
574 assert(key);
575 assert(value);
576 assert(fds);
577
578 if (streq(key, "state")) {
579 TimerState state;
580
581 state = timer_state_from_string(value);
582 if (state < 0)
583 log_debug_unit(u->id, "Failed to parse state value %s", value);
584 else
585 t->deserialized_state = state;
586 } else if (streq(key, "result")) {
587 TimerResult f;
588
589 f = timer_result_from_string(value);
590 if (f < 0)
591 log_debug_unit(u->id, "Failed to parse result value %s", value);
592 else if (f != TIMER_SUCCESS)
593 t->result = f;
594 } else if (streq(key, "last-trigger-realtime")) {
595
596 r = safe_atou64(value, &t->last_trigger.realtime);
597 if (r < 0)
598 log_debug_unit(u->id, "Failed to parse last-trigger-realtime value %s", value);
599
600 } else if (streq(key, "last-trigger-monotonic")) {
601
602 r = safe_atou64(value, &t->last_trigger.monotonic);
603 if (r < 0)
604 log_debug_unit(u->id, "Failed to parse last-trigger-monotonic value %s", value);
605
606 } else
607 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
608
609 return 0;
610 }
611
612 _pure_ static UnitActiveState timer_active_state(Unit *u) {
613 assert(u);
614
615 return state_translation_table[TIMER(u)->state];
616 }
617
618 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
619 assert(u);
620
621 return timer_state_to_string(TIMER(u)->state);
622 }
623
624 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
625 Timer *t = TIMER(userdata);
626
627 assert(t);
628
629 if (t->state != TIMER_WAITING)
630 return 0;
631
632 log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
633 timer_enter_running(t);
634 return 0;
635 }
636
637 static void timer_trigger_notify(Unit *u, Unit *other) {
638 Timer *t = TIMER(u);
639 TimerValue *v;
640
641 assert(u);
642 assert(other);
643
644 if (other->load_state != UNIT_LOADED)
645 return;
646
647 /* Reenable all timers that depend on unit state */
648 LIST_FOREACH(value, v, t->values)
649 if (v->base == TIMER_UNIT_ACTIVE ||
650 v->base == TIMER_UNIT_INACTIVE)
651 v->disabled = false;
652
653 switch (t->state) {
654
655 case TIMER_WAITING:
656 case TIMER_ELAPSED:
657
658 /* Recalculate sleep time */
659 timer_enter_waiting(t, false);
660 break;
661
662 case TIMER_RUNNING:
663
664 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
665 log_debug_unit(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
666 timer_enter_waiting(t, false);
667 }
668 break;
669
670 case TIMER_DEAD:
671 case TIMER_FAILED:
672 break;
673
674 default:
675 assert_not_reached("Unknown timer state");
676 }
677 }
678
679 static void timer_reset_failed(Unit *u) {
680 Timer *t = TIMER(u);
681
682 assert(t);
683
684 if (t->state == TIMER_FAILED)
685 timer_set_state(t, TIMER_DEAD);
686
687 t->result = TIMER_SUCCESS;
688 }
689
690 static void timer_time_change(Unit *u) {
691 Timer *t = TIMER(u);
692
693 assert(u);
694
695 if (t->state != TIMER_WAITING)
696 return;
697
698 log_debug_unit(u->id, "%s: time change, recalculating next elapse.", u->id);
699 timer_enter_waiting(t, false);
700 }
701
702 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
703 [TIMER_DEAD] = "dead",
704 [TIMER_WAITING] = "waiting",
705 [TIMER_RUNNING] = "running",
706 [TIMER_ELAPSED] = "elapsed",
707 [TIMER_FAILED] = "failed"
708 };
709
710 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
711
712 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
713 [TIMER_ACTIVE] = "OnActiveSec",
714 [TIMER_BOOT] = "OnBootSec",
715 [TIMER_STARTUP] = "OnStartupSec",
716 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
717 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
718 [TIMER_CALENDAR] = "OnCalendar"
719 };
720
721 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
722
723 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
724 [TIMER_SUCCESS] = "success",
725 [TIMER_FAILURE_RESOURCES] = "resources"
726 };
727
728 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
729
730 const UnitVTable timer_vtable = {
731 .object_size = sizeof(Timer),
732
733 .sections =
734 "Unit\0"
735 "Timer\0"
736 "Install\0",
737
738 .init = timer_init,
739 .done = timer_done,
740 .load = timer_load,
741
742 .coldplug = timer_coldplug,
743
744 .dump = timer_dump,
745
746 .start = timer_start,
747 .stop = timer_stop,
748
749 .serialize = timer_serialize,
750 .deserialize_item = timer_deserialize_item,
751
752 .active_state = timer_active_state,
753 .sub_state_to_string = timer_sub_state_to_string,
754
755 .trigger_notify = timer_trigger_notify,
756
757 .reset_failed = timer_reset_failed,
758 .time_change = timer_time_change,
759
760 .bus_interface = "org.freedesktop.systemd1.Timer",
761 .bus_vtable = bus_timer_vtable,
762 };